panda-core 0.2.4 → 0.6.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/app/assets/tailwind/application.css +199 -7
- data/app/assets/tailwind/tailwind.config.js +8 -0
- data/app/components/panda/core/UI/badge.rb +107 -0
- data/app/components/panda/core/UI/button.rb +110 -0
- data/app/components/panda/core/UI/card.rb +88 -0
- data/app/components/panda/core/admin/breadcrumb_component.rb +133 -0
- data/app/components/panda/core/admin/button_component.rb +46 -28
- data/app/components/panda/core/admin/container_component.rb +75 -4
- data/app/components/panda/core/admin/file_gallery_component.rb +157 -0
- data/app/components/panda/core/admin/flash_message_component.rb +98 -15
- data/app/components/panda/core/admin/form_error_component.rb +48 -0
- data/app/components/panda/core/admin/form_input_component.rb +50 -0
- data/app/components/panda/core/admin/form_select_component.rb +68 -0
- data/app/components/panda/core/admin/heading_component.rb +53 -24
- data/app/components/panda/core/admin/page_header_component.rb +107 -0
- data/app/components/panda/core/admin/panel_component.rb +33 -4
- data/app/components/panda/core/admin/slideover_component.rb +66 -4
- data/app/components/panda/core/admin/statistics_component.rb +19 -0
- data/app/components/panda/core/admin/tab_bar_component.rb +101 -0
- data/app/components/panda/core/admin/table_component.rb +92 -11
- data/app/components/panda/core/admin/tag_component.rb +58 -16
- data/app/components/panda/core/admin/user_activity_component.rb +43 -0
- data/app/components/panda/core/admin/user_display_component.rb +77 -0
- data/app/components/panda/core/base.rb +122 -0
- data/app/controllers/panda/core/admin/base_controller.rb +68 -0
- data/app/controllers/panda/core/admin/dashboard_controller.rb +5 -3
- data/app/controllers/panda/core/admin/my_profile_controller.rb +4 -4
- data/app/controllers/panda/core/admin/sessions_controller.rb +15 -8
- data/app/controllers/panda/core/admin/test_sessions_controller.rb +60 -0
- data/app/helpers/panda/core/asset_helper.rb +31 -5
- data/app/helpers/panda/core/sessions_helper.rb +27 -2
- data/app/javascript/panda/core/application.js +8 -1
- data/app/javascript/panda/core/controllers/alert_controller.js +38 -0
- data/app/javascript/panda/core/controllers/index.js +3 -3
- data/app/javascript/panda/core/controllers/toggle_controller.js +41 -0
- data/app/javascript/panda/core/tailwindplus-elements.js +31 -0
- data/app/javascript/panda/core/vendor/@hotwired--stimulus.js +4 -0
- data/app/javascript/panda/core/vendor/@hotwired--turbo.js +160 -0
- data/app/javascript/panda/core/vendor/@rails--actioncable--src.js +4 -0
- data/app/models/panda/core/user.rb +61 -14
- data/app/services/panda/core/attach_avatar_service.rb +67 -0
- data/app/views/layouts/panda/core/admin.html.erb +40 -3
- data/app/views/layouts/panda/core/admin_simple.html.erb +6 -0
- data/app/views/panda/core/admin/dashboard/_default_content.html.erb +4 -4
- data/app/views/panda/core/admin/dashboard/show.html.erb +2 -2
- data/app/views/panda/core/admin/my_profile/edit.html.erb +36 -25
- data/app/views/panda/core/admin/sessions/new.html.erb +9 -10
- data/app/views/panda/core/admin/shared/_breadcrumbs.html.erb +27 -34
- data/app/views/panda/core/admin/shared/_flash.html.erb +4 -30
- data/app/views/panda/core/admin/shared/_sidebar.html.erb +41 -20
- data/app/views/panda/core/shared/_header.html.erb +13 -5
- data/config/importmap.rb +19 -6
- data/config/routes.rb +10 -3
- data/db/migrate/20250810120000_add_current_theme_to_panda_core_users.rb +7 -0
- data/db/migrate/20250811120000_add_oauth_avatar_url_to_panda_core_users.rb +7 -0
- data/lib/panda/core/asset_loader.rb +23 -8
- data/lib/panda/core/configuration.rb +12 -9
- data/lib/panda/core/debug.rb +47 -0
- data/lib/panda/core/engine.rb +55 -9
- data/lib/panda/core/services/base_service.rb +19 -4
- data/lib/panda/core/version.rb +1 -1
- data/lib/panda/core.rb +2 -0
- data/lib/tasks/panda_core_users.rake +158 -0
- metadata +103 -14
- data/app/components/panda/core/admin/container_component.html.erb +0 -12
- data/app/components/panda/core/admin/flash_message_component.html.erb +0 -31
- data/app/components/panda/core/admin/panel_component.html.erb +0 -7
- data/app/components/panda/core/admin/slideover_component.html.erb +0 -9
- data/app/components/panda/core/admin/table_component.html.erb +0 -29
- data/app/controllers/panda/core/admin_controller.rb +0 -30
|
@@ -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
|
data/lib/panda/core/engine.rb
CHANGED
|
@@ -13,21 +13,32 @@ 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")]
|
|
22
|
+
config.autoload_paths += Dir[root.join("app", "services")]
|
|
20
23
|
|
|
21
24
|
# Make files in public available to the main app (e.g. /panda-core-assets/panda-logo.png)
|
|
22
|
-
config.
|
|
23
|
-
Rack::Static,
|
|
25
|
+
config.middleware.use Rack::Static,
|
|
24
26
|
urls: ["/panda-core-assets"],
|
|
25
27
|
root: Panda::Core::Engine.root.join("public"),
|
|
26
28
|
header_rules: [
|
|
27
29
|
# Disable caching in development for instant CSS updates
|
|
28
30
|
[:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000"}]
|
|
29
31
|
]
|
|
30
|
-
|
|
32
|
+
|
|
33
|
+
# Make JavaScript files available for importmap
|
|
34
|
+
# Serve from app/javascript with proper MIME types
|
|
35
|
+
config.middleware.use Rack::Static,
|
|
36
|
+
urls: ["/panda", "/panda/core"],
|
|
37
|
+
root: Panda::Core::Engine.root.join("app/javascript"),
|
|
38
|
+
header_rules: [
|
|
39
|
+
[:all, {"Cache-Control" => Rails.env.development? ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000",
|
|
40
|
+
"Content-Type" => "text/javascript; charset=utf-8"}]
|
|
41
|
+
]
|
|
31
42
|
|
|
32
43
|
config.generators do |g|
|
|
33
44
|
g.test_framework :rspec
|
|
@@ -43,7 +54,7 @@ module Panda
|
|
|
43
54
|
end
|
|
44
55
|
end
|
|
45
56
|
|
|
46
|
-
initializer "panda_core.
|
|
57
|
+
initializer "panda_core.config" do |app|
|
|
47
58
|
# Configuration is already initialized with defaults in Configuration class
|
|
48
59
|
end
|
|
49
60
|
|
|
@@ -64,18 +75,18 @@ module Panda
|
|
|
64
75
|
end
|
|
65
76
|
end
|
|
66
77
|
|
|
67
|
-
|
|
68
78
|
initializer "panda_core.omniauth" do |app|
|
|
69
79
|
# Mount OmniAuth at configurable admin path
|
|
70
80
|
app.middleware.use OmniAuth::Builder do
|
|
71
81
|
# Configure OmniAuth to use the configured admin path
|
|
72
82
|
configure do |config|
|
|
73
|
-
config.path_prefix = "#{Panda::Core.
|
|
74
|
-
#
|
|
75
|
-
|
|
83
|
+
config.path_prefix = "#{Panda::Core.config.admin_path}/auth"
|
|
84
|
+
# POST-only for CSRF protection (CVE-2015-9284)
|
|
85
|
+
# All login forms use POST via form_tag method: "post"
|
|
86
|
+
config.allowed_request_methods = [:post]
|
|
76
87
|
end
|
|
77
88
|
|
|
78
|
-
Panda::Core.
|
|
89
|
+
Panda::Core.config.authentication_providers.each do |provider_name, settings|
|
|
79
90
|
# Build provider options, allowing custom path name override
|
|
80
91
|
provider_options = settings[:options] || {}
|
|
81
92
|
|
|
@@ -97,6 +108,41 @@ module Panda
|
|
|
97
108
|
end
|
|
98
109
|
end
|
|
99
110
|
end
|
|
111
|
+
|
|
112
|
+
# Load Phlex base component after Rails application is initialized
|
|
113
|
+
# This ensures Rails.application.routes is available
|
|
114
|
+
initializer "panda_core.phlex_base", after: :load_config_initializers do
|
|
115
|
+
require "phlex"
|
|
116
|
+
require "phlex-rails"
|
|
117
|
+
require "literal"
|
|
118
|
+
require "tailwind_merge"
|
|
119
|
+
|
|
120
|
+
# Load the base component
|
|
121
|
+
require root.join("app/components/panda/core/base")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Set up ViewComponent and Lookbook previews
|
|
125
|
+
initializer "panda_core.view_component" do |app|
|
|
126
|
+
app.config.view_component.preview_paths ||= []
|
|
127
|
+
app.config.view_component.preview_paths << root.join("spec/components/previews")
|
|
128
|
+
|
|
129
|
+
# Add preview directories to autoload paths in development
|
|
130
|
+
if Rails.env.development?
|
|
131
|
+
# Handle frozen autoload_paths array
|
|
132
|
+
if app.config.autoload_paths.frozen?
|
|
133
|
+
app.config.autoload_paths = app.config.autoload_paths.dup
|
|
134
|
+
end
|
|
135
|
+
app.config.autoload_paths << root.join("spec/components/previews")
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Create AdminController alias after controllers are loaded
|
|
140
|
+
# This allows other gems to inherit from Panda::Core::AdminController
|
|
141
|
+
initializer "panda_core.admin_controller_alias", after: :load_config_initializers do
|
|
142
|
+
ActiveSupport.on_load(:action_controller_base) do
|
|
143
|
+
Panda::Core.const_set(:AdminController, Panda::Core::Admin::BaseController) unless Panda::Core.const_defined?(:AdminController)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
100
146
|
end
|
|
101
147
|
end
|
|
102
148
|
end
|
|
@@ -2,18 +2,33 @@ module Panda
|
|
|
2
2
|
module Core
|
|
3
3
|
module Services
|
|
4
4
|
class BaseService
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
# Simple result object for service responses
|
|
6
|
+
class Result
|
|
7
|
+
attr_reader :payload, :errors
|
|
8
|
+
|
|
9
|
+
def initialize(success:, payload: {}, errors: nil)
|
|
10
|
+
@success = success
|
|
11
|
+
@payload = payload
|
|
12
|
+
@errors = errors
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def success?
|
|
16
|
+
@success
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.call(**kwargs)
|
|
21
|
+
new(**kwargs).call
|
|
7
22
|
end
|
|
8
23
|
|
|
9
24
|
private
|
|
10
25
|
|
|
11
26
|
def success(payload = {})
|
|
12
|
-
|
|
27
|
+
Result.new(success: true, payload: payload)
|
|
13
28
|
end
|
|
14
29
|
|
|
15
30
|
def failure(errors)
|
|
16
|
-
|
|
31
|
+
Result.new(success: false, errors: errors)
|
|
17
32
|
end
|
|
18
33
|
end
|
|
19
34
|
end
|
data/lib/panda/core/version.rb
CHANGED
data/lib/panda/core.rb
CHANGED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :panda do
|
|
4
|
+
namespace :core do
|
|
5
|
+
namespace :users do
|
|
6
|
+
desc "List all users with their admin status"
|
|
7
|
+
task list: :environment do
|
|
8
|
+
users = Panda::Core::User.all.order(:email)
|
|
9
|
+
|
|
10
|
+
if users.empty?
|
|
11
|
+
puts "No users found."
|
|
12
|
+
else
|
|
13
|
+
puts "\nUsers:"
|
|
14
|
+
puts "-" * 80
|
|
15
|
+
users.each do |user|
|
|
16
|
+
admin_badge = user.admin? ? "[ADMIN]" : ""
|
|
17
|
+
puts "#{user.email.ljust(40)} #{admin_badge}"
|
|
18
|
+
end
|
|
19
|
+
puts "-" * 80
|
|
20
|
+
puts "Total: #{users.count} (#{Panda::Core::User.admins.count} admins)"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc "Grant admin privileges to a user by email (EMAIL=user@example.com)"
|
|
25
|
+
task grant_admin: :environment do
|
|
26
|
+
email = ENV["EMAIL"]
|
|
27
|
+
|
|
28
|
+
unless email
|
|
29
|
+
puts "Error: EMAIL parameter is required"
|
|
30
|
+
puts "Usage: rails panda:core:users:grant_admin EMAIL=user@example.com"
|
|
31
|
+
exit 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
user = Panda::Core::User.find_by(email: email.downcase)
|
|
35
|
+
|
|
36
|
+
unless user
|
|
37
|
+
puts "Error: User with email '#{email}' not found"
|
|
38
|
+
puts "\nExisting users:"
|
|
39
|
+
Panda::Core::User.all.each do |u|
|
|
40
|
+
puts " - #{u.email}"
|
|
41
|
+
end
|
|
42
|
+
exit 1
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if user.admin?
|
|
46
|
+
puts "User '#{user.email}' is already an admin"
|
|
47
|
+
else
|
|
48
|
+
user.update!(is_admin: true)
|
|
49
|
+
puts "✓ Granted admin privileges to '#{user.email}'"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
desc "Revoke admin privileges from a user by email (EMAIL=user@example.com)"
|
|
54
|
+
task revoke_admin: :environment do
|
|
55
|
+
email = ENV["EMAIL"]
|
|
56
|
+
|
|
57
|
+
unless email
|
|
58
|
+
puts "Error: EMAIL parameter is required"
|
|
59
|
+
puts "Usage: rails panda:core:users:revoke_admin EMAIL=user@example.com"
|
|
60
|
+
exit 1
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
user = Panda::Core::User.find_by(email: email.downcase)
|
|
64
|
+
|
|
65
|
+
unless user
|
|
66
|
+
puts "Error: User with email '#{email}' not found"
|
|
67
|
+
exit 1
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if user.admin?
|
|
71
|
+
# Safety check: prevent revoking the last admin
|
|
72
|
+
if Panda::Core::User.admins.count == 1
|
|
73
|
+
puts "Error: Cannot revoke admin privileges from the last admin user"
|
|
74
|
+
puts "Please create another admin first"
|
|
75
|
+
exit 1
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
user.update!(is_admin: false)
|
|
79
|
+
puts "✓ Revoked admin privileges from '#{user.email}'"
|
|
80
|
+
else
|
|
81
|
+
puts "User '#{user.email}' is not an admin"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
desc "Create a new admin user (EMAIL=user@example.com FIRSTNAME=John LASTNAME=Doe)"
|
|
86
|
+
task create_admin: :environment do
|
|
87
|
+
email = ENV["EMAIL"]
|
|
88
|
+
firstname = ENV["FIRSTNAME"] || "Admin"
|
|
89
|
+
lastname = ENV["LASTNAME"] || "User"
|
|
90
|
+
|
|
91
|
+
unless email
|
|
92
|
+
puts "Error: EMAIL parameter is required"
|
|
93
|
+
puts "Usage: rails panda:core:users:create_admin EMAIL=user@example.com FIRSTNAME=John LASTNAME=Doe"
|
|
94
|
+
exit 1
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
existing_user = Panda::Core::User.find_by(email: email.downcase)
|
|
98
|
+
|
|
99
|
+
if existing_user
|
|
100
|
+
puts "Error: User with email '#{email}' already exists"
|
|
101
|
+
if existing_user.admin?
|
|
102
|
+
puts "This user is already an admin"
|
|
103
|
+
else
|
|
104
|
+
puts "Use 'rails panda:core:users:grant_admin EMAIL=#{email}' to make them an admin"
|
|
105
|
+
end
|
|
106
|
+
exit 1
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Build attributes hash based on schema
|
|
110
|
+
attributes = {
|
|
111
|
+
email: email.downcase,
|
|
112
|
+
is_admin: true
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Add name attributes based on schema
|
|
116
|
+
if Panda::Core::User.column_names.include?("name")
|
|
117
|
+
attributes[:name] = "#{firstname} #{lastname}".strip
|
|
118
|
+
elsif Panda::Core::User.column_names.include?("firstname") && Panda::Core::User.column_names.include?("lastname")
|
|
119
|
+
attributes[:firstname] = firstname
|
|
120
|
+
attributes[:lastname] = lastname
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
user = Panda::Core::User.create!(attributes)
|
|
124
|
+
puts "✓ Created admin user '#{user.email}'"
|
|
125
|
+
puts " Name: #{user.name}" if user.respond_to?(:name)
|
|
126
|
+
puts " Admin: #{user.admin?}"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
desc "Delete a user by email (EMAIL=user@example.com)"
|
|
130
|
+
task delete: :environment do
|
|
131
|
+
email = ENV["EMAIL"]
|
|
132
|
+
|
|
133
|
+
unless email
|
|
134
|
+
puts "Error: EMAIL parameter is required"
|
|
135
|
+
puts "Usage: rails panda:core:users:delete EMAIL=user@example.com"
|
|
136
|
+
exit 1
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
user = Panda::Core::User.find_by(email: email.downcase)
|
|
140
|
+
|
|
141
|
+
unless user
|
|
142
|
+
puts "Error: User with email '#{email}' not found"
|
|
143
|
+
exit 1
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Safety check: prevent deleting the last admin
|
|
147
|
+
if user.admin? && Panda::Core::User.admins.count == 1
|
|
148
|
+
puts "Error: Cannot delete the last admin user"
|
|
149
|
+
puts "Please create another admin first"
|
|
150
|
+
exit 1
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
user.destroy!
|
|
154
|
+
puts "✓ Deleted user '#{email}'"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: panda-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Otaina Limited
|
|
8
8
|
- James Inman
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: importmap-rails
|
|
@@ -165,6 +164,62 @@ dependencies:
|
|
|
165
164
|
- - ">="
|
|
166
165
|
- !ruby/object:Gem::Version
|
|
167
166
|
version: '0'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: phlex
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - "~>"
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '2.3'
|
|
174
|
+
type: :runtime
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - "~>"
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '2.3'
|
|
181
|
+
- !ruby/object:Gem::Dependency
|
|
182
|
+
name: phlex-rails
|
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - "~>"
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '2.3'
|
|
188
|
+
type: :runtime
|
|
189
|
+
prerelease: false
|
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - "~>"
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '2.3'
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: literal
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "~>"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '1.8'
|
|
202
|
+
type: :runtime
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - "~>"
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: '1.8'
|
|
209
|
+
- !ruby/object:Gem::Dependency
|
|
210
|
+
name: tailwind_merge
|
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
|
212
|
+
requirements:
|
|
213
|
+
- - "~>"
|
|
214
|
+
- !ruby/object:Gem::Version
|
|
215
|
+
version: '1.3'
|
|
216
|
+
type: :runtime
|
|
217
|
+
prerelease: false
|
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
219
|
+
requirements:
|
|
220
|
+
- - "~>"
|
|
221
|
+
- !ruby/object:Gem::Version
|
|
222
|
+
version: '1.3'
|
|
168
223
|
- !ruby/object:Gem::Dependency
|
|
169
224
|
name: pg
|
|
170
225
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -193,6 +248,20 @@ dependencies:
|
|
|
193
248
|
- - ">="
|
|
194
249
|
- !ruby/object:Gem::Version
|
|
195
250
|
version: '0'
|
|
251
|
+
- !ruby/object:Gem::Dependency
|
|
252
|
+
name: rails-controller-testing
|
|
253
|
+
requirement: !ruby/object:Gem::Requirement
|
|
254
|
+
requirements:
|
|
255
|
+
- - ">="
|
|
256
|
+
- !ruby/object:Gem::Version
|
|
257
|
+
version: '0'
|
|
258
|
+
type: :development
|
|
259
|
+
prerelease: false
|
|
260
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
261
|
+
requirements:
|
|
262
|
+
- - ">="
|
|
263
|
+
- !ruby/object:Gem::Version
|
|
264
|
+
version: '0'
|
|
196
265
|
- !ruby/object:Gem::Dependency
|
|
197
266
|
name: capybara
|
|
198
267
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -364,7 +433,7 @@ dependencies:
|
|
|
364
433
|
description: Shared development tools, configurations, and utilities for Panda CMS
|
|
365
434
|
and its related projects
|
|
366
435
|
email:
|
|
367
|
-
-
|
|
436
|
+
- james@otaina.co.uk
|
|
368
437
|
executables: []
|
|
369
438
|
extensions: []
|
|
370
439
|
extra_rdoc_files: []
|
|
@@ -375,36 +444,54 @@ files:
|
|
|
375
444
|
- app/assets/tailwind/application.css
|
|
376
445
|
- app/assets/tailwind/tailwind.config.js
|
|
377
446
|
- app/builders/panda/core/form_builder.rb
|
|
447
|
+
- app/components/panda/core/UI/badge.rb
|
|
448
|
+
- app/components/panda/core/UI/button.rb
|
|
449
|
+
- app/components/panda/core/UI/card.rb
|
|
450
|
+
- app/components/panda/core/admin/breadcrumb_component.rb
|
|
378
451
|
- app/components/panda/core/admin/button_component.rb
|
|
379
|
-
- app/components/panda/core/admin/container_component.html.erb
|
|
380
452
|
- app/components/panda/core/admin/container_component.rb
|
|
381
|
-
- app/components/panda/core/admin/
|
|
453
|
+
- app/components/panda/core/admin/file_gallery_component.rb
|
|
382
454
|
- app/components/panda/core/admin/flash_message_component.rb
|
|
455
|
+
- app/components/panda/core/admin/form_error_component.rb
|
|
456
|
+
- app/components/panda/core/admin/form_input_component.rb
|
|
457
|
+
- app/components/panda/core/admin/form_select_component.rb
|
|
383
458
|
- app/components/panda/core/admin/heading_component.rb
|
|
384
|
-
- app/components/panda/core/admin/
|
|
459
|
+
- app/components/panda/core/admin/page_header_component.rb
|
|
385
460
|
- app/components/panda/core/admin/panel_component.rb
|
|
386
|
-
- app/components/panda/core/admin/slideover_component.html.erb
|
|
387
461
|
- app/components/panda/core/admin/slideover_component.rb
|
|
388
|
-
- app/components/panda/core/admin/
|
|
462
|
+
- app/components/panda/core/admin/statistics_component.rb
|
|
463
|
+
- app/components/panda/core/admin/tab_bar_component.rb
|
|
389
464
|
- app/components/panda/core/admin/table_component.rb
|
|
390
465
|
- app/components/panda/core/admin/tag_component.rb
|
|
466
|
+
- app/components/panda/core/admin/user_activity_component.rb
|
|
467
|
+
- app/components/panda/core/admin/user_display_component.rb
|
|
468
|
+
- app/components/panda/core/base.rb
|
|
391
469
|
- app/constraints/panda/core/admin_constraint.rb
|
|
470
|
+
- app/controllers/panda/core/admin/base_controller.rb
|
|
392
471
|
- app/controllers/panda/core/admin/dashboard_controller.rb
|
|
393
472
|
- app/controllers/panda/core/admin/my_profile_controller.rb
|
|
394
473
|
- app/controllers/panda/core/admin/sessions_controller.rb
|
|
395
|
-
- app/controllers/panda/core/
|
|
474
|
+
- app/controllers/panda/core/admin/test_sessions_controller.rb
|
|
396
475
|
- app/controllers/panda/core/application_controller.rb
|
|
397
476
|
- app/helpers/panda/core/asset_helper.rb
|
|
398
477
|
- app/helpers/panda/core/sessions_helper.rb
|
|
399
478
|
- app/javascript/panda/core/application.js
|
|
479
|
+
- app/javascript/panda/core/controllers/alert_controller.js
|
|
400
480
|
- app/javascript/panda/core/controllers/index.js
|
|
401
481
|
- app/javascript/panda/core/controllers/theme_form_controller.js
|
|
482
|
+
- app/javascript/panda/core/controllers/toggle_controller.js
|
|
402
483
|
- app/javascript/panda/core/tailwindcss-stimulus-components.js
|
|
484
|
+
- app/javascript/panda/core/tailwindplus-elements.js
|
|
485
|
+
- app/javascript/panda/core/vendor/@hotwired--stimulus.js
|
|
486
|
+
- app/javascript/panda/core/vendor/@hotwired--turbo.js
|
|
487
|
+
- app/javascript/panda/core/vendor/@rails--actioncable--src.js
|
|
403
488
|
- app/models/panda/core/application_record.rb
|
|
404
489
|
- app/models/panda/core/breadcrumb.rb
|
|
405
490
|
- app/models/panda/core/current.rb
|
|
406
491
|
- app/models/panda/core/user.rb
|
|
492
|
+
- app/services/panda/core/attach_avatar_service.rb
|
|
407
493
|
- app/views/layouts/panda/core/admin.html.erb
|
|
494
|
+
- app/views/layouts/panda/core/admin_simple.html.erb
|
|
408
495
|
- app/views/panda/core/admin/dashboard/_default_content.html.erb
|
|
409
496
|
- app/views/panda/core/admin/dashboard/show.html.erb
|
|
410
497
|
- app/views/panda/core/admin/my_profile/edit.html.erb
|
|
@@ -419,6 +506,8 @@ files:
|
|
|
419
506
|
- config/initializers/panda_core.rb
|
|
420
507
|
- config/routes.rb
|
|
421
508
|
- db/migrate/20250809000001_create_panda_core_users.rb
|
|
509
|
+
- db/migrate/20250810120000_add_current_theme_to_panda_core_users.rb
|
|
510
|
+
- db/migrate/20250811120000_add_oauth_avatar_url_to_panda_core_users.rb
|
|
422
511
|
- lib/generators/panda/core/authentication/templates/reek_spec.rb
|
|
423
512
|
- lib/generators/panda/core/dev_tools/USAGE
|
|
424
513
|
- lib/generators/panda/core/dev_tools/templates/lefthook.yml
|
|
@@ -433,6 +522,7 @@ files:
|
|
|
433
522
|
- lib/panda/core/authentication.rb
|
|
434
523
|
- lib/panda/core/component_registry.rb
|
|
435
524
|
- lib/panda/core/configuration.rb
|
|
525
|
+
- lib/panda/core/debug.rb
|
|
436
526
|
- lib/panda/core/engine.rb
|
|
437
527
|
- lib/panda/core/media.rb
|
|
438
528
|
- lib/panda/core/notifications.rb
|
|
@@ -451,6 +541,7 @@ files:
|
|
|
451
541
|
- lib/tasks/panda/core/migrations.rake
|
|
452
542
|
- lib/tasks/panda_core.rake
|
|
453
543
|
- lib/tasks/panda_core_tasks.rake
|
|
544
|
+
- lib/tasks/panda_core_users.rake
|
|
454
545
|
homepage: https://github.com/tastybamboo/panda-core
|
|
455
546
|
licenses:
|
|
456
547
|
- BSD-3-Clause
|
|
@@ -458,7 +549,6 @@ metadata:
|
|
|
458
549
|
homepage_uri: https://github.com/tastybamboo/panda-core
|
|
459
550
|
source_code_uri: https://github.com/tastybamboo/panda-core
|
|
460
551
|
changelog_uri: https://github.com/tastybamboo/panda-core/blob/main/CHANGELOG.md
|
|
461
|
-
post_install_message:
|
|
462
552
|
rdoc_options: []
|
|
463
553
|
require_paths:
|
|
464
554
|
- lib
|
|
@@ -473,8 +563,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
473
563
|
- !ruby/object:Gem::Version
|
|
474
564
|
version: '0'
|
|
475
565
|
requirements: []
|
|
476
|
-
rubygems_version: 3.
|
|
477
|
-
signing_key:
|
|
566
|
+
rubygems_version: 3.6.9
|
|
478
567
|
specification_version: 4
|
|
479
568
|
summary: Core libraries and development tools for Tasty Bamboo projects
|
|
480
569
|
test_files: []
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<main class="overflow-auto flex-1 h-full min-h-full max-h-full">
|
|
2
|
-
<div class="overflow-auto px-2 pt-4 mx-auto sm:px-6 lg:px-6">
|
|
3
|
-
<%= heading %>
|
|
4
|
-
<%= tab_bar %>
|
|
5
|
-
<section class="flex-auto h-[calc(100vh-10rem)]">
|
|
6
|
-
<div class="flex-1 mt-4 w-full h-full">
|
|
7
|
-
<%= content %>
|
|
8
|
-
</div>
|
|
9
|
-
<%= slideover %>
|
|
10
|
-
</section>
|
|
11
|
-
</div>
|
|
12
|
-
</main>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<div class="fixed top-2 right-2 z-[9999] p-2 space-y-4 w-full max-w-sm sm:items-end"
|
|
2
|
-
data-controller="alert"
|
|
3
|
-
<% if @temporary %> data-alert-dismiss-after-value="3000"<% end %>
|
|
4
|
-
data-transition-enter="ease-in-out duration-500"
|
|
5
|
-
data-transition-enter-from="translate-x-full opacity-0"
|
|
6
|
-
data-transition-enter-to="translate-x-0 opacity-100"
|
|
7
|
-
data-transition-leave="ease-in-out duration-500"
|
|
8
|
-
data-transition-leave-from="translate-x-0 opacity-100"
|
|
9
|
-
data-transition-leave-to="translate-x-full opacity-0">
|
|
10
|
-
<div class="overflow-hidden w-full max-w-sm bg-white rounded-lg ring-1 ring-black ring-opacity-5 shadow-lg">
|
|
11
|
-
<div class="p-4">
|
|
12
|
-
<div class="flex items-start">
|
|
13
|
-
<div class="flex-shrink-0">
|
|
14
|
-
<i class="fa-regular text-xl <%= icon_css %> <%= text_colour_css %>"></i>
|
|
15
|
-
</div>
|
|
16
|
-
<div class="flex-1 pt-0.5 ml-3 w-0">
|
|
17
|
-
<p class="mb-1 text-sm font-medium flash-message-title <%= text_colour_css %>"><%= kind.to_s.titleize %></p>
|
|
18
|
-
<p class="mt-1 mb-0 text-sm text-gray-500 flash-message-text"><%= message %></p>
|
|
19
|
-
</div>
|
|
20
|
-
<div class="flex flex-shrink-0 ml-4">
|
|
21
|
-
<button data-action="alert#close" type="button" class="inline-flex text-gray-400 bg-white rounded-md transition duration-150 ease-in-out hover:text-gray-500 focus:ring-2 focus:ring-offset-2 focus:outline-none focus:ring-sky-500">
|
|
22
|
-
<span class="sr-only">Close</span>
|
|
23
|
-
<svg class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
24
|
-
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
|
|
25
|
-
</svg>
|
|
26
|
-
</button>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
<div class="table overflow-x-auto mb-12 w-full rounded-lg border border-gray-500">
|
|
2
|
-
<div class="table-header-group">
|
|
3
|
-
<div class="table-row text-base font-medium text-white bg-gray-500">
|
|
4
|
-
<% columns.each_with_index do |column, i| %>
|
|
5
|
-
<div class="table-cell sticky top-0 z-10 p-4 <% if i.zero? %>rounded-tl-md<% elsif i == columns.size - 1 %>rounded-tr-md<% end %>"><%= column.label %></div>
|
|
6
|
-
<% end %>
|
|
7
|
-
</div>
|
|
8
|
-
</div>
|
|
9
|
-
|
|
10
|
-
<% if @rows.any? %>
|
|
11
|
-
<div class="table-row-group">
|
|
12
|
-
<% @rows.each do |row| %>
|
|
13
|
-
<div class="table-row relative bg-gray-500/5 hover:bg-gray-500/20" data-post-id="<%= row.id %>">
|
|
14
|
-
<% @columns.each do |column| %>
|
|
15
|
-
<div class="table-cell py-5 px-3 h-20 text-sm align-middle whitespace-nowrap border-b border-gray-500/20">
|
|
16
|
-
<%= view_context.capture(row, &column.cell) %>
|
|
17
|
-
</div>
|
|
18
|
-
<% end %>
|
|
19
|
-
</div>
|
|
20
|
-
<% end %>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
<% else %>
|
|
24
|
-
</div>
|
|
25
|
-
<div class="text-center mx-12 block border border-dashed py-12 rounded-lg">
|
|
26
|
-
<h3 class="py-1 text-xl font-semibold text-gray-900">No <%= @term.pluralize %></h3>
|
|
27
|
-
<p class="py-1 text-base text-gray-500">Get started by creating a new <%= @term %>.</p>
|
|
28
|
-
</div>
|
|
29
|
-
<% end %>
|