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.
- checksums.yaml +4 -4
- data/README.md +185 -0
- data/app/assets/tailwind/application.css +182 -0
- data/app/assets/tailwind/tailwind.config.js +21 -0
- data/app/controllers/panda/core/admin/dashboard_controller.rb +2 -3
- data/app/controllers/panda/core/admin/sessions_controller.rb +20 -2
- data/app/controllers/panda/core/admin_controller.rb +2 -0
- data/app/helpers/panda/core/sessions_helper.rb +21 -0
- data/app/javascript/panda/core/application.js +1 -0
- data/app/views/layouts/panda/core/admin.html.erb +5 -59
- data/app/views/panda/core/admin/dashboard/_default_content.html.erb +73 -0
- data/app/views/panda/core/admin/dashboard/show.html.erb +2 -8
- data/app/views/panda/core/admin/sessions/new.html.erb +8 -7
- data/app/views/panda/core/shared/_footer.html.erb +2 -0
- data/app/views/panda/core/shared/_header.html.erb +11 -0
- data/config/importmap.rb +10 -0
- data/config/initializers/panda_core.rb +37 -1
- data/config/routes.rb +7 -5
- data/lib/generators/panda/core/install_generator.rb +3 -9
- data/lib/generators/panda/core/templates/README +25 -0
- data/lib/generators/panda/core/templates/initializer.rb +28 -0
- data/lib/panda/core/configuration.rb +32 -3
- data/lib/panda/core/engine.rb +40 -3
- data/lib/panda/core/version.rb +1 -1
- data/lib/tasks/assets.rake +58 -392
- data/lib/tasks/panda_core_tasks.rake +16 -0
- metadata +11 -2
|
@@ -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-
|
|
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/#{
|
|
15
|
-
<button type="submit" id="button-sign-in-<%=
|
|
16
|
-
|
|
17
|
-
|
|
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,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 %>">
|
data/config/importmap.rb
ADDED
|
@@ -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
|
-
|
|
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
|
-
#
|
|
3
|
-
|
|
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
|
-
|
|
16
|
-
|
|
16
|
+
# Dashboard and admin routes - authentication handled by AdminController
|
|
17
|
+
get "/", to: "admin/dashboard#show", as: :root
|
|
17
18
|
|
|
18
|
-
|
|
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/
|
|
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
|
|
37
|
-
|
|
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 = "
|
|
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
|
data/lib/panda/core/engine.rb
CHANGED
|
@@ -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],
|
|
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],
|
|
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],
|
|
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
|