Class: RailsOmnibar

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_omnibar.rb,
lib/rails_omnibar/items.rb,
lib/rails_omnibar/config.rb,
lib/rails_omnibar/engine.rb,
lib/rails_omnibar/version.rb,
lib/rails_omnibar/commands.rb,
lib/rails_omnibar/item/base.rb,
lib/rails_omnibar/item/help.rb,
lib/rails_omnibar/rendering.rb,
lib/rails_omnibar/conditions.rb,
lib/rails_omnibar/inheritance.rb,
lib/rails_omnibar/command/base.rb,
lib/rails_omnibar/item/webadmin.rb,
lib/rails_omnibar/command/search.rb

Defined Under Namespace

Modules: Command, Item Classes: BaseController, Engine, HtmlController, JsController, QueriesController

Constant Summary collapse

VERSION =
'1.9.0'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.cast_to_command(arg) ⇒ Object



15
16
17
18
19
20
21
# File 'lib/rails_omnibar/commands.rb', line 15

def self.cast_to_command(arg)
  case arg
  when Command::Base then arg
  when Hash          then Command::Base.new(**arg)
  else raise(ArgumentError, "expected command, got #{arg.class}")
  end
end

.cast_to_condition(arg) ⇒ Object



2
3
4
5
6
7
8
# File 'lib/rails_omnibar/conditions.rb', line 2

def self.cast_to_condition(arg)
  case arg
  when nil, true, false then arg
  else
    arg.try(:arity) == 0 ? arg : RailsOmnibar.cast_to_proc(arg)
  end
end

.cast_to_item(arg) ⇒ Object



12
13
14
15
16
17
18
# File 'lib/rails_omnibar/items.rb', line 12

def self.cast_to_item(arg)
  case arg
  when Item::Base then arg
  when Hash       then Item::Base.new(**arg)
  else raise(ArgumentError, "expected Item, got #{arg.class}")
  end
end

.cast_to_proc(arg) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rails_omnibar/commands.rb', line 23

def self.cast_to_proc(arg)
  arg = arg.method(:call).to_proc if arg.respond_to?(:call) && !arg.is_a?(Proc)
  arg.is_a?(Proc) && arg.parameters.count { |type, _| type == :req } == 1 ||
    raise(ArgumentError, "must be a proc that takes one positional argument")

  if arg.arity == 1
    # normalize for easier calling
    return ->(v, controller:, omnibar:) { arg.call(v) }
  end

  unsupported = arg.parameters.reject do |type, name|
    type == :req || type == :keyreq && name.in?(%i[controller omnibar])
  end
  unsupported.empty? ||
    raise(ArgumentError, "unsupported proc params: #{unsupported}")

  arg
end

.evaluate_condition(condition, context:, omnibar:) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/rails_omnibar/conditions.rb', line 10

def self.evaluate_condition(condition, context:, omnibar:)
  case condition
  when nil, true then true
  when false     then false
  else
    context || raise(<<~EOS)
      Missing context for condition, please render the omnibar with `.render(self)`
    EOS
    if condition.try(:arity) == 0
      context.instance_exec(&condition)
    elsif condition.respond_to?(:call)
      condition.call(context, controller: context, omnibar: omnibar)
    else
      raise("unsupported condition type: #{condition.class}")
    end
  end
end

.inherited(subclass) ⇒ Object



2
3
4
5
6
7
8
# File 'lib/rails_omnibar/inheritance.rb', line 2

def self.inherited(subclass)
  bar1 = singleton
  bar2 = subclass.send(:singleton)
  %i[@commands @config @items].each do |ivar|
    bar2.instance_variable_set(ivar, bar1.instance_variable_get(ivar).dup)
  end
end

.likeObject



73
74
75
# File 'lib/rails_omnibar/command/search.rb', line 73

def self.like
  @like ||= ActiveRecord::Base.connection.adapter_name =~ /^post|pg/i ? 'ILIKE' : 'LIKE'
end

Instance Method Details

#add_active_admin_items(icon: default_admin_item_icon, prefix: nil, suffix: nil, suggested: false) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/rails_omnibar/item/webadmin.rb', line 13

def add_active_admin_items(icon: default_admin_item_icon, prefix: nil, suffix: nil, suggested: false)
  ActiveAdmin.load!

  ActiveAdmin.application.namespaces.each do |namespace|
    namespace.fetch_menu(ActiveAdmin::DEFAULT_MENU) # ensure menu is loaded

    namespace.resources.each do |res|
      next unless (res.controller.action_methods & ['index', :index]).any?
      next unless index = res.route_collection_path rescue next
      next unless label = res.menu_item&.label.presence
      label = label.call if label.respond_to?(:call)

      title = [prefix, label, suffix].compact.join(' ')
      add_item(title: title, url: index, icon: icon, suggested: suggested)
    end
  end
end

#add_command(command) ⇒ Object



9
10
11
12
13
# File 'lib/rails_omnibar/commands.rb', line 9

def add_command(command)
  commands << RailsOmnibar.cast_to_command(command)
  clear_command_pattern_cache
  self.class
end

#add_help(**kwargs) ⇒ Object



2
3
4
# File 'lib/rails_omnibar/item/help.rb', line 2

def add_help(**kwargs)
  add_item Item::Help.new(for_commands: commands, **kwargs)
end

#add_item(item) ⇒ Object



2
3
4
5
# File 'lib/rails_omnibar/items.rb', line 2

def add_item(item)
  items << RailsOmnibar.cast_to_item(item)
  self.class
end

#add_items(*args) ⇒ Object



7
8
9
10
# File 'lib/rails_omnibar/items.rb', line 7

def add_items(*args)
  args.each { |arg| add_item(arg) }
  self.class
end

#add_rails_admin_items(icon: default_admin_item_icon, prefix: nil, suffix: nil, suggested: false) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/rails_omnibar/item/webadmin.rb', line 31

def add_rails_admin_items(icon: default_admin_item_icon, prefix: nil, suffix: nil, suggested: false)
  admin_urls = RailsAdmin::Engine.routes.url_helpers

  RailsAdmin::Config.models.select(&:visible?).each do |model|
    next unless index = admin_urls.index_path(model.abstract_model.to_param)
    next unless label = model.label_plural # as used by rails_admin in sidebar

    title = [prefix, label, suffix].compact.join(' ')
    add_item(title: title, url: index, icon: icon, suggested: suggested)
  end
end

#add_record_search(**kwargs) ⇒ Object



6
7
8
# File 'lib/rails_omnibar/command/search.rb', line 6

def add_record_search(**kwargs)
  add_command Command::RecordSearch.new(**kwargs)
end

#add_search(**kwargs) ⇒ Object



2
3
4
# File 'lib/rails_omnibar/command/search.rb', line 2

def add_search(**kwargs)
  add_command Command::Search.new(**kwargs)
end

#add_webadmin_items(icon: default_admin_item_icon, prefix: nil, suffix: nil, suggested: false) ⇒ Object

adds fuzzy-searchable links to each defined resource index of ActiveAdmin etc.



3
4
5
6
7
8
9
10
11
# File 'lib/rails_omnibar/item/webadmin.rb', line 3

def add_webadmin_items(icon: default_admin_item_icon, prefix: nil, suffix: nil, suggested: false)
  if defined?(ActiveAdmin)
    add_active_admin_items(icon: icon, prefix: prefix, suffix: suffix, suggested: suggested)
  elsif defined?(RailsAdmin)
    add_rails_admin_items(icon: icon, prefix: prefix, suffix: suffix, suggested: suggested)
  else
    raise "#{__method__} currently only works with ActiveAdmin or RailsAdmin"
  end
end

#as_jsonObject



18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/rails_omnibar/rendering.rb', line 18

def as_json(*)
  {
    calculator:     calculator?,
    commandPattern: command_pattern,
    hotkey:         hotkey,
    items:          items.select { |i| i.render?(context: @context, omnibar: self) },
    maxResults:     max_results,
    modal:          modal?,
    placeholder:    placeholder,
    queryPath:      urls.query_path(omnibar_class: omnibar_class),
  }
end

#authObject



10
11
12
# File 'lib/rails_omnibar/config.rb', line 10

def auth
  config[:auth]
end

#auth=(arg) ⇒ Object



7
8
9
# File 'lib/rails_omnibar/config.rb', line 7

def auth=(arg)
  config[:auth] = arg.try(:arity) == 0 ? arg : RailsOmnibar.cast_to_proc(arg)
end

#authorize(controller) ⇒ Object



13
14
15
16
17
18
19
20
21
# File 'lib/rails_omnibar/config.rb', line 13

def authorize(controller)
  if auth.nil?
    true
  elsif auth.arity == 0
    controller.instance_exec(&auth)
  else
    auth.call(controller, controller: controller, omnibar: self)
  end
end

#calculator=(arg) ⇒ Object



38
39
40
# File 'lib/rails_omnibar/config.rb', line 38

def calculator=(arg)
  config[:calculator] = arg
end

#calculator?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/rails_omnibar/config.rb', line 41

def calculator?
  config.key?(:calculator) ? !!config[:calculator] : true
end

#configure(&block) ⇒ Object



2
3
4
5
# File 'lib/rails_omnibar/config.rb', line 2

def configure(&block)
  tap(&block)
  self.class
end

#default_admin_item_iconObject



43
44
45
# File 'lib/rails_omnibar/item/webadmin.rb', line 43

def default_admin_item_icon
  :document
end

#handle(input, controller) ⇒ Object



2
3
4
5
6
7
# File 'lib/rails_omnibar/commands.rb', line 2

def handle(input, controller)
  handler = commands.find do |cmd|
    cmd.handle?(input, controller: controller, omnibar: self)
  end
  handler&.call(input, controller: controller, omnibar: self) || []
end

#hotkeyObject



49
50
51
# File 'lib/rails_omnibar/config.rb', line 49

def hotkey
  config[:hotkey] || 'k'
end

#hotkey=(arg) ⇒ Object



45
46
47
48
# File 'lib/rails_omnibar/config.rb', line 45

def hotkey=(arg)
  arg.to_s.size == 1 || raise(ArgumentError, 'hotkey must have length 1')
  config[:hotkey] = arg.to_s.downcase
end

#html_urlObject



12
13
14
# File 'lib/rails_omnibar/rendering.rb', line 12

def html_url
  urls.html_path(omnibar_class: omnibar_class)
end

#max_resultsObject



27
28
29
# File 'lib/rails_omnibar/config.rb', line 27

def max_results
  config[:max_results] || 10
end

#max_results=(arg) ⇒ Object



23
24
25
26
# File 'lib/rails_omnibar/config.rb', line 23

def max_results=(arg)
  arg.is_a?(Integer) && arg > 0 || raise(ArgumentError, 'max_results must be > 0')
  config[:max_results] = arg
end

#modal=(arg) ⇒ Object



31
32
33
# File 'lib/rails_omnibar/config.rb', line 31

def modal=(arg)
  config[:modal] = arg
end

#modal?Boolean

Returns:

  • (Boolean)


34
35
36
# File 'lib/rails_omnibar/config.rb', line 34

def modal?
  config.key?(:modal) ? !!config[:modal] : false
end

#placeholderObject



56
57
58
59
60
61
# File 'lib/rails_omnibar/config.rb', line 56

def placeholder
  return config[:placeholder].presence unless config[:placeholder].nil?

  help_item = items.find { |i| i.type == :help }
  help_item && "Hint: Type `#{help_item.title}` for help"
end

#placeholder=(arg) ⇒ Object



53
54
55
# File 'lib/rails_omnibar/config.rb', line 53

def placeholder=(arg)
  config[:placeholder] = arg
end

#render(context = nil) ⇒ Object



2
3
4
5
6
7
8
9
10
# File 'lib/rails_omnibar/rendering.rb', line 2

def render(context = nil)
  @context = context
  <<~HTML.html_safe
    <script src='#{urls.js_path}?v=#{RailsOmnibar::VERSION}' type='text/javascript'></script>
    <div class='mount-rails-omnibar'>
      <script type="application/json">#{to_json}</script>
    </div>
  HTML
end

#urlsObject



31
32
33
# File 'lib/rails_omnibar/rendering.rb', line 31

def urls
  @urls ||= RailsOmnibar::Engine.routes.url_helpers
end