Class: Panda::Core::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/panda/core/configuration.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfiguration

Returns a new instance of Configuration.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/panda/core/configuration.rb', line 55

def initialize
  @user_class = "Panda::Core::User"
  @user_identity_class = "Panda::Core::UserIdentity"
  @storage_provider = :active_storage
  @cache_store = :memory_store
  @parent_controller = "ActionController::API"
  @parent_mailer = "ActionMailer::Base"
  @auto_mount_engine = true
  @mailer_sender = "support@example.com"
  @mailer_default_url_options = {host: "localhost:3000"}
  @session_token_cookie = :panda_session
  @authentication_providers = {}
  @authentication_provider_resolver = nil
  @authentication_provider_gate = nil
  @authentication_validator = nil
  @admin_path = "/admin"
  @default_theme = "default"

  # Hook system for extending admin UI with sensible defaults
  @admin_navigation_items = ->(user) {
    items = [
      {
        label: "Dashboard",
        path: @admin_path,
        icon: "fa-solid fa-house"
      }
    ]

    # Add CMS navigation if available
    if defined?(Panda::CMS)
      items << {
        label: "Content",
        path: "#{@admin_path}/cms",
        icon: "fa-solid fa-file-lines"
      }
    end

    items << {
      label: "My Profile",
      path: "#{@admin_path}/my_profile/edit",
      icon: "fa-solid fa-user"
    }

    items << {
      label: "Settings",
      icon: "fa-solid fa-gear",
      children: [
        {label: "Feature Flags", path: "#{@admin_path}/feature_flags"}
      ]
    }

    items
  }
  @admin_dashboard_widgets = ->(user) { [] }
  @user_attributes = []
  @user_associations = []
  @authorization_policy = ->(user, action, resource) { user.admin? }

  # Profile and UI customization
  @additional_user_params = []
  # Themes offered in the My Profile dropdown as [label, value] pairs.
  # Assigning this REPLACES the default list — host apps registering
  # their own theme should include any built-ins they still want, e.g.
  #   config.available_themes = [["Default", "default"], ["Acme", "acme"]]
  # The value is stamped as <html data-theme="..."> on admin pages;
  # supply the matching html[data-theme='...'] variable block via
  # config.additional_head_content (see app/assets/tailwind/application.css).
  @available_themes = [["Default", "default"], ["Sky", "sky"]]
  @login_logo_path = nil
  @login_page_title = "Panda Admin"
  @admin_title = "Panda Admin"
  @admin_logo = nil  # Proc/lambda returning HTML for sidebar logo area (e.g. SVG + title)
  @admin_settings_path = nil  # Path for the settings gear icon in the logo area (nil hides it)
  @admin_logo_actions = []  # Array of {path:, icon:, title:} hashes rendered as icon links next to the settings gear
  @admin_sidebar_footer = nil  # Proc/lambda returning HTML for the bottom of the sidebar (replaces version text)
  @initial_admin_breadcrumb = nil  # Proc that returns [label, path]
  @dashboard_redirect_path = nil  # Path to redirect to after login (defaults to admin_root_path)
  @additional_head_content = nil  # Proc/lambda returning HTML to inject into <head> (e.g. theme stylesheets, fonts)

  # Avatar configuration
  @avatar_variants = {
    thumb: {resize_to_limit: [50, 50]},
    small: {resize_to_limit: [100, 100]},
    medium: {resize_to_limit: [200, 200]},
    large: {resize_to_limit: [400, 400]}
  }
  @avatar_max_file_size = 5.megabytes
  @avatar_max_dimension = 800
  @avatar_optimization_quality = 85
  @avatar_image_processor = :vips # or :mini_magick

  # Navigation density — false (spacious, default) or true (compact, for apps with many nav items)
  @compact_navigation = false

  # User management hooks — Procs that host apps set to inject content into user views/callbacks
  @admin_user_edit_content = nil   # Proc(user, form_builder, view_context) → HTML
  @admin_user_after_update = nil   # Proc(user, params, current_user)
  @admin_user_show_content = nil   # Proc(user, view_context) → HTML
  @admin_user_index_columns = nil  # Proc(user, view_context) → HTML

  # Authentication restriction — when truthy, find_or_create_from_auth_hash
  # will NOT create new User records for unknown emails on OAuth login.
  # Accepts a boolean or a callable (receives auth_hash, returns truthy to restrict).
  @restrict_user_creation = false

  # Invitation hooks — host app can extend the invite flow
  @after_user_invited = nil        # Proc(user, params, current_user) — called after successful invite
  @invite_form_content = nil       # Proc(form_builder, view_context) → HTML — extra fields in invite form

  # Post-authentication redirect — Proc(user, request) → URL string or nil.
  # Called after successful OAuth login. Return a URL to redirect there,
  # or nil to fall through to the default redirect logic.
  @post_authentication_redirect = nil

  # Legacy extensible user menu items (prefer NavigationRegistry with position: :bottom)
  @admin_user_menu_items = []

  # Register default user menu as a bottom navigation section (idempotent)
  register_default_user_menu
end

Instance Attribute Details

#additional_head_contentObject

Returns the value of attribute additional_head_content.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def additional_head_content
  @additional_head_content
end

#additional_user_paramsObject

Returns the value of attribute additional_user_params.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def additional_user_params
  @additional_user_params
end

#admin_dashboard_widgetsObject

Returns the value of attribute admin_dashboard_widgets.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_dashboard_widgets
  @admin_dashboard_widgets
end

#admin_logoObject

Returns the value of attribute admin_logo.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def 
  @admin_logo
end

#admin_logo_actionsObject

Returns the value of attribute admin_logo_actions.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_logo_actions
  @admin_logo_actions
end

#admin_navigation_itemsObject

Returns the value of attribute admin_navigation_items.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_navigation_items
  @admin_navigation_items
end

#admin_pathObject

Returns the value of attribute admin_path.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_path
  @admin_path
end

#admin_settings_pathObject

Returns the value of attribute admin_settings_path.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_settings_path
  @admin_settings_path
end

Returns the value of attribute admin_sidebar_footer.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_sidebar_footer
  @admin_sidebar_footer
end

#admin_titleObject

Returns the value of attribute admin_title.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_title
  @admin_title
end

#admin_user_after_updateObject

Returns the value of attribute admin_user_after_update.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_user_after_update
  @admin_user_after_update
end

#admin_user_edit_contentObject

Returns the value of attribute admin_user_edit_content.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_user_edit_content
  @admin_user_edit_content
end

#admin_user_index_columnsObject

Returns the value of attribute admin_user_index_columns.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_user_index_columns
  @admin_user_index_columns
end

#admin_user_menu_itemsObject

Returns the value of attribute admin_user_menu_items.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_user_menu_items
  @admin_user_menu_items
end

#admin_user_show_contentObject

Returns the value of attribute admin_user_show_content.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def admin_user_show_content
  @admin_user_show_content
end

#after_user_invitedObject

Returns the value of attribute after_user_invited.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def after_user_invited
  @after_user_invited
end

#authentication_provider_gateObject

Returns the value of attribute authentication_provider_gate.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def authentication_provider_gate
  @authentication_provider_gate
end

#authentication_provider_resolverObject

Returns the value of attribute authentication_provider_resolver.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def authentication_provider_resolver
  @authentication_provider_resolver
end

#authentication_providersObject

Returns the value of attribute authentication_providers.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def authentication_providers
  @authentication_providers
end

#authentication_validatorObject

Returns the value of attribute authentication_validator.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def authentication_validator
  @authentication_validator
end

#authorization_policyObject

Returns the value of attribute authorization_policy.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def authorization_policy
  @authorization_policy
end

#auto_mount_engineObject

Returns the value of attribute auto_mount_engine.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def auto_mount_engine
  @auto_mount_engine
end

#available_themesObject

Returns the value of attribute available_themes.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def available_themes
  @available_themes
end

#avatar_image_processorObject

Returns the value of attribute avatar_image_processor.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def avatar_image_processor
  @avatar_image_processor
end

#avatar_max_dimensionObject

Returns the value of attribute avatar_max_dimension.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def avatar_max_dimension
  @avatar_max_dimension
end

#avatar_max_file_sizeObject

Returns the value of attribute avatar_max_file_size.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def avatar_max_file_size
  @avatar_max_file_size
end

#avatar_optimization_qualityObject

Returns the value of attribute avatar_optimization_quality.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def avatar_optimization_quality
  @avatar_optimization_quality
end

#avatar_variantsObject

Returns the value of attribute avatar_variants.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def avatar_variants
  @avatar_variants
end

#cache_storeObject

Returns the value of attribute cache_store.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def cache_store
  @cache_store
end

#compact_navigationObject

Returns the value of attribute compact_navigation.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def compact_navigation
  @compact_navigation
end

#dashboard_redirect_pathObject

Returns the value of attribute dashboard_redirect_path.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def dashboard_redirect_path
  @dashboard_redirect_path
end

#default_themeObject

Returns the value of attribute default_theme.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def default_theme
  @default_theme
end

#initial_admin_breadcrumbObject

Returns the value of attribute initial_admin_breadcrumb.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def initial_admin_breadcrumb
  @initial_admin_breadcrumb
end

#invite_form_contentObject

Returns the value of attribute invite_form_content.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def invite_form_content
  @invite_form_content
end

#login_logo_pathObject

Returns the value of attribute login_logo_path.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def 
  @login_logo_path
end

#login_page_titleObject

Returns the value of attribute login_page_title.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def 
  @login_page_title
end

#mailer_default_url_optionsObject

Returns the value of attribute mailer_default_url_options.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def mailer_default_url_options
  @mailer_default_url_options
end

#mailer_senderObject

Returns the value of attribute mailer_sender.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def mailer_sender
  @mailer_sender
end

#parent_controllerObject

Returns the value of attribute parent_controller.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def parent_controller
  @parent_controller
end

#parent_mailerObject

Returns the value of attribute parent_mailer.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def parent_mailer
  @parent_mailer
end

#post_authentication_redirectObject

Returns the value of attribute post_authentication_redirect.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def post_authentication_redirect
  @post_authentication_redirect
end

#restrict_user_creationObject

Returns the value of attribute restrict_user_creation.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def restrict_user_creation
  @restrict_user_creation
end

Returns the value of attribute session_token_cookie.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def session_token_cookie
  @session_token_cookie
end

#storage_providerObject

Returns the value of attribute storage_provider.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def storage_provider
  @storage_provider
end

#user_associationsObject

Returns the value of attribute user_associations.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def user_associations
  @user_associations
end

#user_attributesObject

Returns the value of attribute user_attributes.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def user_attributes
  @user_attributes
end

#user_classObject

Returns the value of attribute user_class.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def user_class
  @user_class
end

#user_identity_classObject

Returns the value of attribute user_identity_class.



6
7
8
# File 'lib/panda/core/configuration.rb', line 6

def user_identity_class
  @user_identity_class
end

Instance Method Details

#filter_admin_menu(label, visible:) ⇒ Object

Register a post-build filter that conditionally hides items by label.

Parameters:

  • label (String)

    Label to match

  • visible (Proc)

    Lambda receiving user — item hidden when false



272
273
274
# File 'lib/panda/core/configuration.rb', line 272

def filter_admin_menu(label, visible:)
  Panda::Core::NavigationRegistry.filter(label, visible: visible)
end

#insert_admin_menu_item(label, section:, path: nil, url: nil, target: nil, visible: nil, permission: nil, before: nil, after: nil, method: nil, button_options: {}, path_helper: nil) ⇒ Object

Register an item to be appended to an existing admin navigation section.

If the target section doesn't exist at build time, the item is silently skipped. Use path: for admin-relative paths or url: for absolute URLs.

rubocop:disable Metrics/ParameterLists

Examples:

Add to an existing section

config.insert_admin_menu_item "Feature Flags",
  section: "Settings",
  path: "feature_flags"

Permission-gated item

config.insert_admin_menu_item "Suggestions",
  section: "Tools",
  path: "cms/content_suggestions",
  permission: :review_content

Parameters:

  • label (String)

    Item label displayed in the sidebar

  • section (String)

    Label of the target section to add to

  • path (String, nil) (defaults to: nil)

    Relative path (auto-prefixed with admin_path)

  • url (String, nil) (defaults to: nil)

    Absolute URL (used as-is, no prefixing)

  • target (String, nil) (defaults to: nil)

    HTML target attribute (e.g. "_blank")

  • visible (Proc, nil) (defaults to: nil)

    Lambda receiving user, hides item when false

  • before (Symbol, String, nil) (defaults to: nil)

    :all or label — position within section

  • after (Symbol, String, nil) (defaults to: nil)

    :all or label — position within section

  • method (Symbol, nil) (defaults to: nil)

    HTTP method (e.g. :delete)

  • button_options (Hash) (defaults to: {})

    Extra options for button_to

  • path_helper (Symbol, nil) (defaults to: nil)

    Route helper resolved at build time

See Also:



244
245
246
247
248
249
250
251
# File 'lib/panda/core/configuration.rb', line 244

def insert_admin_menu_item(label, section:, path: nil, url: nil, target: nil,
  visible: nil, permission: nil, before: nil, after: nil, method: nil, button_options: {}, path_helper: nil)
  Panda::Core::NavigationRegistry.item(
    label, section: section, path: path, url: url, target: target,
    visible: visible, permission: permission, before: before, after: after,
    method: method, button_options: button_options, path_helper: path_helper
  )
end

#insert_admin_menu_section(label, icon: nil, after: nil, before: nil, visible: nil, permission: nil, position: :top) {|NavigationRegistry::SectionContext| ... } ⇒ Object

Register a new admin navigation section via NavigationRegistry.

Sections with the same label as an existing base section are skipped. Use after: or before: to control positioning relative to other sections.

Examples:

Add a section with items

config.insert_admin_menu_section "Members",
  icon: "fa-solid fa-users",
  after: "Website" do |section|
    section.item "Onboarding", path: "members/onboarding"
  end

Parameters:

  • label (String)

    Section label displayed in the sidebar

  • icon (String) (defaults to: nil)

    FontAwesome icon class (e.g. "fa-solid fa-users")

  • after (String, nil) (defaults to: nil)

    Insert after the section with this label

  • before (String, nil) (defaults to: nil)

    Insert before the section with this label

  • visible (Proc, nil) (defaults to: nil)

    Lambda receiving user, hides section when false

  • permission (Symbol, nil) (defaults to: nil)

    Permission key — hides section unless user is authorized

  • position (Symbol) (defaults to: :top)

    :top (default) or :bottom

Yields:

See Also:



210
211
212
# File 'lib/panda/core/configuration.rb', line 210

def insert_admin_menu_section(label, icon: nil, after: nil, before: nil, visible: nil, permission: nil, position: :top, &block)
  Panda::Core::NavigationRegistry.section(label, icon: icon, after: after, before: before, visible: visible, permission: permission, position: position, &block)
end

#insert_admin_user_menu_item(label, path: nil, url: nil, visible: nil, position: :before_logout) ⇒ Object

Convenience: add an item to the user menu (bottom section).

Parameters:

  • label (String)

    Item label

  • path (String, nil) (defaults to: nil)

    Path (auto-prefixed with admin_path)

  • url (String, nil) (defaults to: nil)

    Full URL (used as-is)

  • visible (Proc, nil) (defaults to: nil)

    Lambda receiving user, hides item when false

  • position (Symbol) (defaults to: :before_logout)

    :before_logout (default) or :top



260
261
262
263
264
265
266
267
# File 'lib/panda/core/configuration.rb', line 260

def insert_admin_user_menu_item(label, path: nil, url: nil, visible: nil, position: :before_logout)
  before_opt = (position == :before_logout) ? "Logout" : nil
  before_opt = :all if position == :top
  Panda::Core::NavigationRegistry.item(
    label, section: "My Account", path: path, url: url,
    visible: visible, before: before_opt
  )
end

#register_admin_dashboard_widget(label, component:, visible: nil, position: 0) ⇒ Object

Register a dashboard widget via WidgetRegistry.

Parameters:

  • label (String)

    Widget label

  • component (Proc)

    Lambda receiving user, returns a component instance

  • visible (Proc, nil) (defaults to: nil)

    Lambda receiving user, hides widget when false

  • position (Integer) (defaults to: 0)

    Sort order (lower first)



281
282
283
# File 'lib/panda/core/configuration.rb', line 281

def register_admin_dashboard_widget(label, component:, visible: nil, position: 0)
  Panda::Core::WidgetRegistry.register(label, component: component, visible: visible, position: position)
end

#resolved_authentication_providers(request = nil) ⇒ Object

Returns the authentication providers for the given request. If an authentication_provider_resolver proc is configured it is called with the request to allow per-tenant provider filtering. Otherwise the static authentication_providers hash is returned.



180
181
182
183
184
185
186
# File 'lib/panda/core/configuration.rb', line 180

def resolved_authentication_providers(request = nil)
  if authentication_provider_resolver && request
    authentication_provider_resolver.call(request)
  else
    authentication_providers
  end
end