Module: OpenLoam::Widgets

Defined in:
lib/open_loam/widgets.rb

Overview

A registry of dashboard widgets — small, module-provided tiles (a metric, a short list) shown on the admin home. A widget is a DATA PROVIDER plus a title and an optional role filter; it never renders arbitrary code:

OpenLoam::Widgets.register(key: "open_rentals", title: "Open rentals", roles: %w[manager]) do |actor|
{ kind: "count", value: Rental.where(status: "open").count }   # tenant-scoped query
end

The provider returns a small data hash ({ kind: "count", value: } or { kind: "list", items: [...] }); the dashboard renders it generically. Widgets run tenant-scoped (query through tenant-scoped models), the roles: filter is enforced server-side (a hidden widget's data is NOT computed), and a raising provider is isolated into an error tile — the dashboard never breaks.

Defined Under Namespace

Classes: Widget

Class Method Summary collapse

Class Method Details

.find(key) ⇒ Object



30
# File 'lib/open_loam/widgets.rb', line 30

def find(key) = registry[key.to_s]

.keys ⇒ Object



29
# File 'lib/open_loam/widgets.rb', line 29

def keys = registry.keys

.register(key:, title:, roles: nil, &block) ⇒ Object



23
24
25
26
# File 'lib/open_loam/widgets.rb', line 23

def register(key:, title:, roles: nil, &block)
  registry[key.to_s] = Widget.new(key: key.to_s, title: title, roles: roles, provider: block)
  key.to_s
end

.register_builtins! ⇒ Object

The widgets every OpenLoam app starts with — registered at boot from the engine, so a fresh install has a useful default dashboard.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/open_loam/widgets.rb', line 53

def register_builtins!
  register(key: "audit_recent", title: "Recent activity") do |_actor|
    items = OpenLoam::AuditRecord.order(created_at: :desc).limit(8)
                             .map { |a| "#{a.action} #{a.auditable_type} ##{a.auditable_id}" }
    { kind: "list", items: items }
  end
  register(key: "notifications_unread", title: "Unread notifications") do |actor|
    { kind: "count", value: OpenLoam::Notification.unread.where(user_id: actor&.id).count }
  end
  register(key: "pending_approvals", title: "Pending approvals", roles: %w[manager]) do |_actor|
    { kind: "count", value: OpenLoam::PendingAction.pending.count }
  end
  register(key: "open_progress", title: "Running tasks") do |_actor|
    { kind: "count", value: OpenLoam::ProgressJob.where(status: "running").count }
  end
end

.registered ⇒ Object



28
# File 'lib/open_loam/widgets.rb', line 28

def registered = registry.values

.reset! ⇒ Object



32
33
34
# File 'lib/open_loam/widgets.rb', line 32

def reset!
  @registry = {}
end

.resolve(key, actor:, role:) ⇒ Object

Resolve a widget for (actor, role): nil when it doesn't exist or the role can't see it (so its data is never computed), otherwise { key, title, data } — or { key, title, error: } when the provider raises.



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/open_loam/widgets.rb', line 39

def resolve(key, actor:, role:)
  return nil if OpenLoam::Overrides.disabled?(:widgets, key) # customization without forking

  widget = find(key)
  return nil unless widget&.visible_to?(role)

  provider = OpenLoam::Overrides.replacement(:widgets, key) || widget.provider
  { key: widget.key, title: widget.title, data: provider.call(actor) }
rescue StandardError => error
  { key: widget&.key, title: widget&.title, error: error.message }
end