panda-core 0.9.1 → 0.9.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52d28416fc7360a3f5cc27ec2ad1f332a61426a8279853461dfe7398f180213a
4
- data.tar.gz: f68cd0fbaf803d80a3549f67485328c80850e3d035d42f7c89eb1b15a80f6b64
3
+ metadata.gz: 3e7863be64e4e612a42759b596547772fdc8ea9f50d85dc57b6c879328cbb8fa
4
+ data.tar.gz: 14c99c7ad8e4dd48c69aecf9b958ab9201e77e5159affcdc3bba8bb5a6608998
5
5
  SHA512:
6
- metadata.gz: d71325c49673982b5ae74107eb7e05cb0bd04b12bc64262284392df691b142953fb6f5a25385c4795d605ec243e972ac30cd8688fb4e7f95ebc43e360b7ba5e1
7
- data.tar.gz: b0391beb484a72298375547b4d526e73ce47ea18a1d73864e6e2ef226e25fef961d83c268a5cdab12b5dbc1c08c984696f344bfe0e974d0e9c1a37badafdb035
6
+ metadata.gz: 337d68b1a7c03cedfdcea65f5978d13dc3cd6692d79188dc0132e4fb55a781d3b4c0991a23582e9fae585c88fa58ea314401f1a0cc5a9bc5059617d385536753
7
+ data.tar.gz: 5be39c37ddf7d54f51071bc2486fd33b81e1be1bc1176358c890180de86676ce7848d89b426ecad80663e7a72e371de164fb71b1a3bd82c44e6decd09519bf57
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Panda
4
+ module Core
5
+ module Admin
6
+ class SettingsController < AdminController
7
+ def show
8
+ # Placeholder for site settings page
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -9,6 +9,10 @@ module Panda
9
9
  end
10
10
 
11
11
  # Include only Core JavaScript
12
+ #
13
+ # This is the single entry point for all Panda JavaScript loading.
14
+ # It automatically includes JavaScript from Core and all registered modules
15
+ # via ModuleRegistry.
12
16
  def panda_core_javascript
13
17
  # Use asset_tags for development mode (importmap) compatibility
14
18
  # In development, this will use importmap; in production/test, compiled bundles
@@ -22,20 +26,34 @@ module Panda
22
26
  javascript_include_tag(js_url, type: "module")
23
27
  end
24
28
  else
25
- # Development mode - Use the engine's importmap (loaded in initializer)
26
- # This keeps the engine's JavaScript separate from the app's importmap
27
- # Build the importmap JSON manually since paths are already absolute
28
- imports = {}
29
- Panda::Core.importmap.instance_variable_get(:@packages).each do |name, package|
30
- imports[name] = package[:path]
31
- end
29
+ # Development mode - Use ModuleRegistry to combine all Panda module importmaps
30
+ imports = Panda::Core::ModuleRegistry.combined_importmap
32
31
 
33
32
  importmap_json = JSON.generate({"imports" => imports})
34
33
 
34
+ # Generate entry point script tags for Core and all registered modules
35
+ entry_points = []
36
+
37
+ # Core entry points (always included)
38
+ entry_points << '<script type="module">import "panda/core/application"</script>'
39
+ entry_points << '<script type="module">import "panda/core/controllers/index"</script>'
40
+
41
+ # Add entry points for each registered module
42
+ Panda::Core::ModuleRegistry.modules.each do |gem_name, info|
43
+ # Extract module namespace from gem name (e.g., "panda-cms" -> "cms")
44
+ module_slug = gem_name.sub(/^panda-/, "")
45
+
46
+ # Check if the module is actually loaded
47
+ module_name = info[:engine].sub(/::Engine$/, "")
48
+ next unless Object.const_defined?(module_name)
49
+
50
+ entry_points << %(<script type="module">import "panda/#{module_slug}/application"</script>)
51
+ entry_points << %(<script type="module">import "panda/#{module_slug}/controllers/index"</script>)
52
+ end
53
+
35
54
  <<~HTML.html_safe
36
55
  <script type="importmap">#{importmap_json}</script>
37
- <script type="module">import "panda/core/application"</script>
38
- <script type="module">import "panda/core/controllers/index"</script>
56
+ #{entry_points.join("\n")}
39
57
  HTML
40
58
  end
41
59
  end
@@ -0,0 +1,10 @@
1
+ <%= render Panda::Core::Admin::ContainerComponent.new do %>
2
+ <%= render Panda::Core::Admin::HeadingComponent.new(level: 1, text: "Settings") %>
3
+
4
+ <div class="mt-6 space-y-6">
5
+ <%= render Panda::Core::Admin::PanelComponent.new do %>
6
+ <%= render Panda::Core::Admin::HeadingComponent.new(level: 2, text: "Site Settings") %>
7
+ <p class="text-sm text-gray-600 mt-2">Configure your site settings here.</p>
8
+ <% end %>
9
+ </div>
10
+ <% end %>
@@ -6,11 +6,14 @@
6
6
  <%= csp_meta_tag %>
7
7
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.1.0/css/all.min.css">
8
8
  <%= panda_core_stylesheet %>
9
+
10
+ <!-- ES Module Shims polyfill - must load BEFORE importmap (blocking, not async) -->
11
+ <script src="https://ga.jspm.io/npm:[email protected]/dist/es-module-shims.js" crossorigin="anonymous"></script>
12
+
13
+ <!-- Panda JavaScript (Core + all registered modules via ModuleRegistry) -->
9
14
  <%= panda_core_javascript %>
10
15
 
11
16
  <% if defined?(Panda::CMS) && controller.class.name.start_with?("Panda::CMS") %>
12
- <!-- CMS Assets -->
13
- <%= panda_cms_javascript %>
14
17
  <%= render "panda/cms/shared/favicons" %>
15
18
  <% end %>
16
19
 
data/config/routes.rb CHANGED
@@ -19,6 +19,9 @@ Panda::Core::Engine.routes.draw do
19
19
  # Profile management
20
20
  resource :my_profile, only: %i[show edit update], controller: "admin/my_profile", path: "my_profile"
21
21
 
22
+ # Settings
23
+ resource :settings, only: [:show], controller: "admin/settings"
24
+
22
25
  # Test-only authentication endpoint (available in development and test environments)
23
26
  # This bypasses OAuth for faster, more reliable test execution
24
27
  # Development: Used by Capybara system tests which run Rails server in development mode
@@ -151,8 +151,9 @@ module Panda
151
151
  version = asset_version
152
152
  "/panda-core-assets/panda-core-#{version}.js"
153
153
  else
154
- # Return importmap path
155
- "/assets/panda/core/application.js"
154
+ # Return path for development/test mode
155
+ # JavaScript is served via importmap from app/javascript
156
+ "/panda/core/application.js"
156
157
  end
157
158
  end
158
159
 
@@ -4,29 +4,13 @@ module Panda
4
4
  module Core
5
5
  class Engine < ::Rails::Engine
6
6
  # Middleware configuration for static assets
7
+ # Note: Actual middleware is registered in engine.rb initializer
8
+ # This module is kept for organizational purposes
7
9
  module MiddlewareConfig
8
10
  extend ActiveSupport::Concern
9
11
 
10
- included do
11
- # Make files in public available to the main app (e.g. /panda-core-assets/panda-logo.png)
12
- config.middleware.use Rack::Static,
13
- urls: ["/panda-core-assets"],
14
- root: Panda::Core::Engine.root.join("public"),
15
- header_rules: [
16
- # Disable caching in development for instant CSS updates
17
- [:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000"}]
18
- ]
19
-
20
- # Make JavaScript files available for importmap
21
- # Serve from app/javascript with proper MIME types
22
- config.middleware.use Rack::Static,
23
- urls: ["/panda", "/panda/core"],
24
- root: Panda::Core::Engine.root.join("app/javascript"),
25
- header_rules: [
26
- [:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000",
27
- "Content-Type" => "text/javascript; charset=utf-8"}]
28
- ]
29
- end
12
+ # Middleware configuration moved to engine.rb initializer
13
+ # See lib/panda/core/engine.rb - initializer "panda.core.static_assets"
30
14
  end
31
15
  end
32
16
  end
@@ -57,6 +57,23 @@ module Panda
57
57
  # Configuration is already initialized with defaults in Configuration class
58
58
  end
59
59
 
60
+ # Static asset middleware for serving public files and JavaScript modules
61
+ # Must run before Propshaft to intercept /panda/* requests
62
+ initializer "panda.core.static_assets" do |app|
63
+ # Serve public assets (CSS, images, etc.)
64
+ app.config.middleware.insert_before Propshaft::Server, Rack::Static,
65
+ urls: ["/panda-core-assets"],
66
+ root: Panda::Core::Engine.root.join("public"),
67
+ header_rules: [
68
+ # Disable caching in development for instant CSS updates
69
+ [:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000"}]
70
+ ]
71
+
72
+ # Use ModuleRegistry's custom middleware to serve JavaScript from all registered modules
73
+ # This middleware checks all modules and serves from the first matching location
74
+ app.config.middleware.insert_before Propshaft::Server, Panda::Core::ModuleRegistry::JavaScriptMiddleware
75
+ end
76
+
60
77
  # Auto-compile CSS for test/development environments
61
78
  initializer "panda_core.auto_compile_assets", after: :load_config_initializers do |app|
62
79
  # Only auto-compile in test or when explicitly requested
@@ -104,3 +121,14 @@ module Panda
104
121
  end
105
122
  end
106
123
  end
124
+
125
+ # Register Core module with ModuleRegistry for JavaScript serving
126
+ Panda::Core::ModuleRegistry.register(
127
+ gem_name: "panda-core",
128
+ engine: "Panda::Core::Engine",
129
+ paths: {
130
+ views: "app/views/panda/core/**/*.erb",
131
+ components: "app/components/panda/core/**/*.rb"
132
+ # JavaScript paths are auto-discovered from config/importmap.rb
133
+ }
134
+ )
@@ -144,8 +144,62 @@ module Panda
144
144
  @modules.key?(gem_name)
145
145
  end
146
146
 
147
+ # Returns a combined importmap for all registered modules
148
+ #
149
+ # This merges importmaps from Core and all registered modules (CMS, CMS Pro, etc.)
150
+ # into a single hash suitable for <script type="importmap"> generation.
151
+ #
152
+ # Order matters: Core imports are added first, then modules in registration order.
153
+ # If there are conflicts, later modules override earlier ones.
154
+ #
155
+ # @return [Hash] Combined imports hash {"module/name" => "/path/to/file.js"}
156
+ def combined_importmap
157
+ imports = {}
158
+
159
+ # Add Panda Core imports first (if Core has an importmap)
160
+ if defined?(Panda::Core.importmap)
161
+ Panda::Core.importmap.instance_variable_get(:@packages).each do |name, package|
162
+ imports[name] = package.path
163
+ end
164
+ end
165
+
166
+ # Add registered modules' importmaps in registration order
167
+ @modules.each do |gem_name, info|
168
+ next unless engine_available?(info[:engine])
169
+
170
+ # Get the module's importmap constant (e.g., Panda::CMS.importmap)
171
+ module_importmap = module_importmap_for(info[:engine])
172
+ next unless module_importmap
173
+
174
+ module_importmap.instance_variable_get(:@packages).each do |name, package|
175
+ imports[name] = package.path
176
+ end
177
+ end
178
+
179
+ imports
180
+ end
181
+
147
182
  private
148
183
 
184
+ # Get the importmap for a module
185
+ #
186
+ # @param engine_name [String] Engine constant name (e.g., "Panda::CMS::Engine")
187
+ # @return [Importmap::Map, nil] Module's importmap or nil if not available
188
+ def module_importmap_for(engine_name)
189
+ # Extract module namespace from engine name (e.g., "Panda::CMS::Engine" -> "Panda::CMS")
190
+ module_name = engine_name.sub(/::Engine$/, "")
191
+ return nil unless Object.const_defined?(module_name)
192
+
193
+ mod = Object.const_get(module_name)
194
+ return nil unless mod.respond_to?(:importmap)
195
+
196
+ mod.importmap
197
+ rescue NoMethodError
198
+ nil
199
+ rescue NameError
200
+ nil
201
+ end
202
+
149
203
  # Check if an engine constant is defined and available
150
204
  #
151
205
  # @param engine_name [String] Engine constant name
@@ -223,6 +277,99 @@ module Panda
223
277
  nil
224
278
  end
225
279
  end
280
+
281
+ # Custom Rack middleware to serve JavaScript modules from all registered Panda modules
282
+ #
283
+ # This middleware checks all registered modules' app/javascript/panda directories
284
+ # and serves the first matching file. This solves the problem of multiple Rack::Static
285
+ # instances blocking each other.
286
+ #
287
+ class JavaScriptMiddleware
288
+ def initialize(app)
289
+ @app = app
290
+ end
291
+
292
+ def call(env)
293
+ request = Rack::Request.new(env)
294
+ path = request.path_info
295
+
296
+ # Only handle /panda/core/* and /panda/cms/* style JavaScript module requests
297
+ # Skip paths like /panda-core-assets/* (public assets handled by Rack::Static)
298
+ return @app.call(env) unless path.start_with?("/panda/")
299
+
300
+ # Strip /panda/ prefix to get relative path
301
+ # e.g., "/panda/cms/application.js" -> "cms/application.js"
302
+ relative_path = path.sub(%r{^/panda/}, "")
303
+ return @app.call(env) if relative_path.empty?
304
+
305
+ # Try to find the file in registered modules
306
+ file_path = find_javascript_file(relative_path)
307
+
308
+ if file_path && File.file?(file_path)
309
+ puts "[JavaScriptMiddleware] Serving: #{path} from #{file_path}"
310
+ serve_file(file_path, env)
311
+ else
312
+ puts "[JavaScriptMiddleware] Not found: #{path} (tried #{relative_path})"
313
+ @app.call(env)
314
+ end
315
+ rescue => e
316
+ # On error, log and pass to next middleware
317
+ puts "[JavaScriptMiddleware] Error: #{e.message}"
318
+ Rails.logger.error("[ModuleRegistry::JavaScriptMiddleware] Error: #{e.message}\n#{e.backtrace.join("\n")}") if defined?(Rails.logger)
319
+ @app.call(env)
320
+ end
321
+
322
+ private
323
+
324
+ def find_javascript_file(relative_path)
325
+ # Check each registered module's JavaScript directory
326
+ ModuleRegistry.modules.each do |gem_name, info|
327
+ next unless ModuleRegistry.send(:engine_available?, info[:engine])
328
+
329
+ root = ModuleRegistry.send(:engine_root, info[:engine])
330
+ next unless root
331
+
332
+ # Check in app/javascript/panda/
333
+ candidate = root.join("app/javascript/panda", relative_path)
334
+ return candidate.to_s if candidate.exist? && candidate.file?
335
+ end
336
+
337
+ nil
338
+ end
339
+
340
+ def serve_file(file_path, env)
341
+ # Read file content
342
+ content = File.read(file_path)
343
+
344
+ # Determine content type
345
+ content_type = case File.extname(file_path)
346
+ when ".js"
347
+ "application/javascript; charset=utf-8"
348
+ when ".json"
349
+ "application/json; charset=utf-8"
350
+ else
351
+ "text/plain; charset=utf-8"
352
+ end
353
+
354
+ # Determine cache control
355
+ cache_control = if Rails.env.development? || Rails.env.test?
356
+ "no-cache, no-store, must-revalidate"
357
+ else
358
+ "public, max-age=31536000"
359
+ end
360
+
361
+ # Return response
362
+ [
363
+ 200,
364
+ {
365
+ "Content-Type" => content_type,
366
+ "Content-Length" => content.bytesize.to_s,
367
+ "Cache-Control" => cache_control
368
+ },
369
+ [content]
370
+ ]
371
+ end
372
+ end
226
373
  end
227
374
  end
228
375
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ # CI-specific Capybara configuration
4
+ # This file configures Capybara for GitHub Actions and other CI environments
5
+ # It uses a more robust Puma setup with compatibility for Puma 6 and 7+
6
+
7
+ return unless defined?(Capybara)
8
+
9
+ ci_mode = ENV["GITHUB_ACTIONS"] == "true" || ENV["CI_SYSTEM_SPECS"] == "true"
10
+ return unless ci_mode
11
+
12
+ require "rack/handler/puma"
13
+
14
+ RSpec.configure do |config|
15
+ config.before(:suite) do
16
+ Capybara.server = :puma_ci
17
+ Capybara.default_max_wait_time = Integer(ENV.fetch("CAPYBARA_MAX_WAIT_TIME", 5))
18
+ Capybara.server_host = "127.0.0.1"
19
+ Capybara.always_include_port = true
20
+
21
+ puts "[CI Config] Capybara.server = #{Capybara.server.inspect}"
22
+ puts "[CI Config] Capybara.server_host = #{Capybara.server_host.inspect}"
23
+ puts "[CI Config] Capybara.max_wait = #{Capybara.default_max_wait_time}s"
24
+ end
25
+ end
26
+
27
+ Capybara.register_server :puma_ci do |app, port, host|
28
+ puts "[CI Config] Starting Puma (single mode) on #{host}:#{port}"
29
+
30
+ min_threads = Integer(ENV.fetch("PUMA_MIN_THREADS", "2"))
31
+ max_threads = Integer(ENV.fetch("PUMA_MAX_THREADS", "2"))
32
+
33
+ options = {
34
+ Host: host,
35
+ Port: port,
36
+ Threads: "#{min_threads}:#{max_threads}",
37
+ Workers: 0,
38
+ Silent: false,
39
+ Verbose: true,
40
+ PreloadApp: false
41
+ }
42
+
43
+ # --- Puma Compatibility Layer (supports Puma 6 AND Puma 7+) ---
44
+ puma_run = Rack::Handler::Puma.method(:run)
45
+
46
+ if puma_run.arity == 2
47
+ # Puma <= 6.x signature:
48
+ # run(app, options_hash)
49
+ puts "[CI Config] Using Puma <= 6 API (arity 2)"
50
+ Rack::Handler::Puma.run(app, options)
51
+ else
52
+ # Puma >= 7.x signature:
53
+ # run(app, **options)
54
+ puts "[CI Config] Using Puma >= 7 API (keyword args)"
55
+ Rack::Handler::Puma.run(app, **options)
56
+ end
57
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Panda
4
4
  module Core
5
- VERSION = "0.9.1"
5
+ VERSION = "0.9.3"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panda-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Otaina Limited
8
8
  - James Inman
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 1980-01-02 00:00:00.000000000 Z
12
+ date: 2025-11-13 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: image_processing
@@ -429,6 +430,7 @@ files:
429
430
  - app/controllers/panda/core/admin/dashboard_controller.rb
430
431
  - app/controllers/panda/core/admin/my_profile_controller.rb
431
432
  - app/controllers/panda/core/admin/sessions_controller.rb
433
+ - app/controllers/panda/core/admin/settings_controller.rb
432
434
  - app/controllers/panda/core/admin/test_sessions_controller.rb
433
435
  - app/controllers/panda/core/application_controller.rb
434
436
  - app/helpers/panda/core/asset_helper.rb
@@ -456,6 +458,7 @@ files:
456
458
  - app/views/panda/core/admin/dashboard/show.html.erb
457
459
  - app/views/panda/core/admin/my_profile/edit.html.erb
458
460
  - app/views/panda/core/admin/sessions/new.html.erb
461
+ - app/views/panda/core/admin/settings/show.html.erb
459
462
  - app/views/panda/core/admin/shared/_breadcrumbs.html.erb
460
463
  - app/views/panda/core/admin/shared/_flash.html.erb
461
464
  - app/views/panda/core/admin/shared/_sidebar.html.erb
@@ -506,6 +509,7 @@ files:
506
509
  - lib/panda/core/testing/support/setup.rb
507
510
  - lib/panda/core/testing/support/system/better_system_tests.rb
508
511
  - lib/panda/core/testing/support/system/capybara_setup.rb
512
+ - lib/panda/core/testing/support/system/ci_capybara_config.rb
509
513
  - lib/panda/core/testing/support/system/cuprite_helpers.rb
510
514
  - lib/panda/core/testing/support/system/cuprite_setup.rb
511
515
  - lib/panda/core/testing/support/system/database_connection_helpers.rb
@@ -526,6 +530,7 @@ metadata:
526
530
  homepage_uri: https://github.com/tastybamboo/panda-core
527
531
  source_code_uri: https://github.com/tastybamboo/panda-core
528
532
  changelog_uri: https://github.com/tastybamboo/panda-core/blob/main/CHANGELOG.md
533
+ post_install_message:
529
534
  rdoc_options: []
530
535
  require_paths:
531
536
  - lib
@@ -540,7 +545,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
540
545
  - !ruby/object:Gem::Version
541
546
  version: '0'
542
547
  requirements: []
543
- rubygems_version: 3.6.9
548
+ rubygems_version: 3.5.22
549
+ signing_key:
544
550
  specification_version: 4
545
551
  summary: Core libraries and development tools for Tasty Bamboo projects
546
552
  test_files: []