panda-core 0.2.3 → 0.2.4

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.
@@ -3,20 +3,21 @@
3
3
  <% if Panda::Core.configuration.login_logo_path %>
4
4
  <img src="<%= Panda::Core.configuration.login_logo_path %>" class="py-2 mx-auto w-auto h-32">
5
5
  <% end %>
6
- <h2 class="mt-10 mb-6 text-2xl font-bold text-center text-gray-900">
6
+ <h2 class="mt-10 mb-6 text-2xl font-bold text-center text-white">
7
7
  <%= Panda::Core.configuration.login_page_title || "Sign in to your account" %>
8
8
  </h2>
9
9
  </div>
10
10
  <% if @providers&.any? || Panda::Core.configuration.authentication_providers.any? %>
11
11
  <% providers = @providers || Panda::Core.configuration.authentication_providers.keys %>
12
12
  <% providers.each do |provider| %>
13
+ <% provider_config = Panda::Core.configuration.authentication_providers[provider] %>
14
+ <% provider_name = provider_config&.dig(:name) || provider.to_s.humanize %>
15
+ <% provider_path = provider_config&.dig(:path_name) || provider %>
13
16
  <div class="mt-4 text-center sm:mx-auto sm:w-full sm:max-w-sm">
14
- <%= form_tag "#{Panda::Core.configuration.admin_path}/auth/#{provider}", method: "post", data: {turbo: false} do %>
15
- <button type="submit" id="button-sign-in-<%= provider %>" class="inline-flex gap-x-2 items-center py-2.5 px-3.5 mx-auto mb-4 bg-white rounded-md border min-w-56 border-neutral-400">
16
- <% if defined?(FontAwesome) %>
17
- <i class="fa-brands fa-<%= provider %> text-xl mr-1"></i>
18
- <% end %>
19
- Sign in with <%= provider.to_s.humanize %>
17
+ <%= form_tag "#{Panda::Core.configuration.admin_path}/auth/#{provider_path}", method: "post", data: {turbo: false} do %>
18
+ <button type="submit" id="button-sign-in-<%= provider_path %>" class="inline-flex gap-x-2 items-center py-2.5 px-3.5 mx-auto mb-4 bg-white text-gray-900 rounded-md border min-w-56 border-neutral-400 hover:bg-gray-50">
19
+ <i class="fa-brands fa-<%= oauth_provider_icon(provider) %> text-xl mr-1"></i>
20
+ Sign in with <%= provider_name %>
20
21
  </button>
21
22
  <% end %>
22
23
  </div>
@@ -0,0 +1,2 @@
1
+ </body>
2
+ </html>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html data-theme="<%= Panda::Core::Current&.user&.current_theme || Panda::Core.configuration.default_theme %>" class="<%= local_assigns[:html_class] || "" %>">
3
+ <head>
4
+ <title><%= content_for?(:title) ? yield(:title) : (Panda::Core.configuration.admin_title || "Panda Admin") %></title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+ <script src="https://kit.fontawesome.com/7835d81e75.js" defer="true" crossorigin="anonymous"></script>
8
+ <link rel="stylesheet" href="/panda-core-assets/panda-core.css">
9
+ <%= yield :head %>
10
+ </head>
11
+ <body class="h-full <%= local_assigns[:body_class] || "" %>" data-environment="<%= Rails.env %>">
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base JavaScript dependencies for Panda Core
4
+ pin "@hotwired/turbo", to: "@hotwired--turbo.js", preload: true # @8.0.18
5
+ pin "@rails/actioncable/src", to: "@rails--actioncable--src.js", preload: true # @8.0.201
6
+ pin "@hotwired/stimulus", to: "@hotwired--stimulus.js" # @3.2.2
7
+ pin "tailwindcss-stimulus-components" # @6.1.3
8
+
9
+ # Font Awesome icons
10
+ pin "@fortawesome/fontawesome-free", to: "https://ga.jspm.io/npm:@fortawesome/fontawesome-free@7.1.0/js/all.js"
@@ -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.configuration.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,10 +13,11 @@ 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
+ # Profile management
20
+ constraints Panda::Core::AdminConstraint.new do
19
21
  resource :my_profile, only: %i[edit update], controller: "admin/my_profile", path: "my_profile"
20
22
  end
21
23
  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
@@ -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-regular 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-regular fa-file-lines"
59
+ }
60
+ end
61
+
62
+ items << {
63
+ label: "My Profile",
64
+ path: "#{@admin_path}/my_profile/edit",
65
+ icon: "fa-regular fa-user"
66
+ }
67
+
68
+ items
69
+ }
42
70
  @admin_dashboard_widgets = ->(user) { [] }
43
71
  @user_attributes = []
44
72
  @user_associations = []
@@ -48,7 +76,8 @@ 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
@@ -18,6 +18,17 @@ module Panda
18
18
  config.autoload_paths += Dir[root.join("app", "builders")]
19
19
  config.autoload_paths += Dir[root.join("app", "components")]
20
20
 
21
+ # Make files in public available to the main app (e.g. /panda-core-assets/panda-logo.png)
22
+ config.app_middleware.use(
23
+ Rack::Static,
24
+ urls: ["/panda-core-assets"],
25
+ root: Panda::Core::Engine.root.join("public"),
26
+ header_rules: [
27
+ # Disable caching in development for instant CSS updates
28
+ [:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000"}]
29
+ ]
30
+ )
31
+
21
32
  config.generators do |g|
22
33
  g.test_framework :rspec
23
34
  g.fixture_replacement :factory_bot
@@ -36,6 +47,24 @@ module Panda
36
47
  # Configuration is already initialized with defaults in Configuration class
37
48
  end
38
49
 
50
+ # Add importmap paths from the engine
51
+ initializer "panda_core.importmap", before: "importmap" do |app|
52
+ if app.config.respond_to?(:importmap)
53
+ # Create a new array if frozen
54
+ app.config.importmap.paths = app.config.importmap.paths.dup if app.config.importmap.paths.frozen?
55
+
56
+ # Add our paths
57
+ app.config.importmap.paths << root.join("config/importmap.rb")
58
+
59
+ # Handle cache sweepers similarly
60
+ if app.config.importmap.cache_sweepers.frozen?
61
+ app.config.importmap.cache_sweepers = app.config.importmap.cache_sweepers.dup
62
+ end
63
+ app.config.importmap.cache_sweepers << root.join("app/javascript")
64
+ end
65
+ end
66
+
67
+
39
68
  initializer "panda_core.omniauth" do |app|
40
69
  # Mount OmniAuth at configurable admin path
41
70
  app.middleware.use OmniAuth::Builder do
@@ -47,13 +76,21 @@ module Panda
47
76
  end
48
77
 
49
78
  Panda::Core.configuration.authentication_providers.each do |provider_name, settings|
79
+ # Build provider options, allowing custom path name override
80
+ provider_options = settings[:options] || {}
81
+
82
+ # If path_name is specified, use it to override the default strategy name in URLs
83
+ if settings[:path_name].present?
84
+ provider_options = provider_options.merge(name: settings[:path_name])
85
+ end
86
+
50
87
  case provider_name.to_s
51
88
  when "microsoft_graph"
52
- provider :microsoft_graph, settings[:client_id], settings[:client_secret], settings[:options] || {}
89
+ provider :microsoft_graph, settings[:client_id], settings[:client_secret], provider_options
53
90
  when "google_oauth2"
54
- provider :google_oauth2, settings[:client_id], settings[:client_secret], settings[:options] || {}
91
+ provider :google_oauth2, settings[:client_id], settings[:client_secret], provider_options
55
92
  when "github"
56
- provider :github, settings[:client_id], settings[:client_secret], settings[:options] || {}
93
+ provider :github, settings[:client_id], settings[:client_secret], provider_options
57
94
  when "developer"
58
95
  provider :developer if Rails.env.development?
59
96
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Panda
4
4
  module Core
5
- VERSION = "0.2.3"
5
+ VERSION = "0.2.4"
6
6
  end
7
7
  end