Module: RivetCms::Navigation
- Defined in:
- lib/rivet_cms/navigation.rb
Overview
Admin sidebar registry: the seam the Pro engine adds nav items through. Core registers its own items here too, so every item, core or extension, goes through the same can? filter and a denied user never sees a link that would 403.
RivetCms::Navigation.register :audit_log,
label: "Audit Log",
section: "Manage",
icon: :content,
requires: [:read, :content],
path: -> { audit_log_path },
position: 80
path is either a string or a lambda instance_exec'd in the controller, so engine route helpers work directly. requires is [action, resource] for can?, or nil for always visible. icon names one of the built-in sidebar icons; unknown names render a neutral dot. Items sort by position across sections; a section appears where its lowest-position item falls. Re-registering a key replaces the item, so registration is reload-safe.
Defined Under Namespace
Classes: Item
Constant Summary collapse
- MUTEX =
Mutex.new
Class Method Summary collapse
- .items ⇒ Object
- .register(key, label:, section:, path:, icon: nil, requires: nil, position: 100, exact: false, badge: nil, visible: nil) ⇒ Object
- .restore(snapshot) ⇒ Object
-
.snapshot ⇒ Object
Test-only: capture registrations so an example can add items and hand the registry back exactly as it found it.
- .unregister(key) ⇒ Object
Class Method Details
.items ⇒ Object
51 52 53 |
# File 'lib/rivet_cms/navigation.rb', line 51 def items mutex.synchronize { registry.values.sort_by.with_index { |item, index| [ item.position, index ] } } end |
.register(key, label:, section:, path:, icon: nil, requires: nil, position: 100, exact: false, badge: nil, visible: nil) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/rivet_cms/navigation.rb', line 27 def register(key, label:, section:, path:, icon: nil, requires: nil, position: 100, exact: false, badge: nil, visible: nil) raise ArgumentError, "label required" if label.to_s.strip.empty? raise ArgumentError, "path must be a String or callable" unless path.is_a?(String) || path.respond_to?(:call) # Class equality, not is_a?: ActiveSupport::Duration answers is_a?(Integer) raise ArgumentError, "position must be an Integer" unless position.class == Integer raise ArgumentError, "badge must be callable" unless badge.nil? || badge.respond_to?(:call) raise ArgumentError, "visible must be callable" unless visible.nil? || visible.respond_to?(:call) unless requires.nil? || (requires.is_a?(Array) && requires.size == 2 && requires.all? { |part| part.respond_to?(:to_sym) }) raise ArgumentError, "requires must be nil or [action, resource]" end item = Item.new( key: key.to_sym, label: label.to_s, section: section.to_s, icon: icon&.to_sym, requires: requires&.map(&:to_sym), path: path, position: position, exact: exact == true, badge: badge, visible: visible ) mutex.synchronize { registry[item.key] = item } item end |
.restore(snapshot) ⇒ Object
61 62 63 64 65 |
# File 'lib/rivet_cms/navigation.rb', line 61 def restore(snapshot) return if snapshot.nil? # never mistake a failed snapshot for "no items" mutex.synchronize { @registry = snapshot.dup } end |
.snapshot ⇒ Object
Test-only: capture registrations so an example can add items and hand the registry back exactly as it found it.
57 58 59 |
# File 'lib/rivet_cms/navigation.rb', line 57 def snapshot mutex.synchronize { registry.dup } end |
.unregister(key) ⇒ Object
47 48 49 |
# File 'lib/rivet_cms/navigation.rb', line 47 def unregister(key) mutex.synchronize { registry.delete(key.to_sym) } end |