rails_omnibar 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07132bcc31a15ed0d5ba925a00bf25ac2656babd01c15e8df03ac41b46897512
4
- data.tar.gz: f18ef9526a35db7790b4c79ae597df3bbcf4ab93273e245ba753650b427453ca
3
+ metadata.gz: d860d3dad8c472ba1b2ea46adc5b99c22eea4a846ad98ec025d78b36ecede83e
4
+ data.tar.gz: fac209673acca1f5102c6162ff1eb597ff6b9d3588987535c991dd17cbd3c40a
5
5
  SHA512:
6
- metadata.gz: 25e3eb51a271cb5c229a6850c138f783a828b6b08434625ebca9aa75ea16c7368073eaf52260270ea1599c74734a7662cc0f0c8be700295c4aa062b26018efc8
7
- data.tar.gz: a4e5a52e52eadaedc34018b95f79aaf084c6310d0bb1a33fd68188736e7a7028bbaa6c3ed090788d7e256b8df5f15989c562791f6fe389192a8220f0596fe6ca
6
+ metadata.gz: 76cdf9f017b33261eecf4e84c4f00f6dcca277c84f21107073eca5f4e53c50370d33697a7f56db22cb9b8a51645d21c082d94cecb1f21c09b876f3b46a4a855d
7
+ data.tar.gz: 6d8bb4548482b948ce79b1f4d38189453b37d5d95ddd8e7cac9c7b095b263c8ae369feb8b8d9a5a8cb57a844a0c9e1bbb34b562ba41f62acb72903e113b05e2c
data/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.7.0] - 2024-07-02
8
+
9
+ ### Added
10
+
11
+ - conditional rendering of items (`add_item(if: ->{ ... })`)
12
+ - conditional execution of commands (`add_command(if: ->{ ... })`)
13
+ - inheritance of items, commands, and configuration (`Bar2 = Class.new(Bar1)`)
14
+
7
15
  ## [1.6.0] - 2024-01-25
8
16
 
9
17
  ### Added
data/Gemfile CHANGED
@@ -12,7 +12,7 @@ group :development, :test do
12
12
  gem 'puma', '~> 6.0'
13
13
  gem 'rake', '~> 13.0'
14
14
  gem 'rspec-rails', '~> 5.0'
15
- gem 'sqlite3', '>= 1.3.6'
15
+ gem 'sqlite3', '~> 1.4'
16
16
  gem 'sprockets-rails', '~> 3.4' # for activeadmin
17
17
  gem 'webdrivers', '~> 5.0'
18
18
  end
data/README.md CHANGED
@@ -89,14 +89,14 @@ end
89
89
  Render it somewhere. E.g. `app/views/layouts/application.html.erb`:
90
90
 
91
91
  ```erb
92
- <%= Omnibar.render %>
92
+ <%= Omnibar.render(self) %>
93
93
  ```
94
94
 
95
95
  If you have a fully decoupled frontend, use `Omnibar.html_url` instead, fetch the omnibar HTML from there, and inject it.
96
96
 
97
97
  ### Authorization
98
98
 
99
- You can limit access to commands (e.g. search commands). This will not limit access to plain items.
99
+ You can limit access to commands (e.g. search commands) and items.
100
100
 
101
101
  #### Option 1: globally limit engine access
102
102
 
@@ -119,19 +119,35 @@ MyOmnibar.auth = ->(controller, omnibar:) do
119
119
  end
120
120
  ```
121
121
 
122
+ #### Option 3: Item-level conditionality
123
+
124
+ Items and commands can have an `if` proc that is executed in the controller context. If it returns false, the item is not shown and the command is not executed.
125
+
126
+ ```ruby
127
+ MyOmnibar.add_item(
128
+ title: 'Admin link',
129
+ url: admin_url,
130
+ if: ->{ current_user.admin? }
131
+ )
132
+ ```
133
+
134
+ For this to work, the controller context must be given to the omnibar when rendering (e.g. by passing `self` in a view):
135
+
136
+ ```erb
137
+ <%= Omnibar.render(self) %>
138
+ ```
139
+
122
140
  ### Using multiple different omnibars
123
141
 
124
142
  ```ruby
125
- BaseOmnibar = Class.new(RailsOmnibar)
126
- BaseOmnibar.configure do |c|
143
+ BaseOmnibar = Class.new(RailsOmnibar).configure do |c|
127
144
  c.add_item(
128
145
  title: 'Log in',
129
146
  url: Rails.application.routes.url_helpers.log_in_url
130
147
  )
131
148
  end
132
149
 
133
- UserOmnibar = Class.new(RailsOmnibar)
134
- UserOmnibar.configure do |c|
150
+ UserOmnibar = Class.new(RailsOmnibar).configure do |c|
135
151
  c.auth = ->{ user_signed_in? }
136
152
  c.add_item(
137
153
  title: 'Log out',
@@ -143,7 +159,15 @@ end
143
159
  Then, in some layout:
144
160
 
145
161
  ```erb
146
- <%= (user_signed_in? ? UserOmnibar : BaseOmnibar).render %>
162
+ <%= (user_signed_in? ? UserOmnibar : BaseOmnibar).render(self) %>
163
+ ```
164
+
165
+ Omnibars can also inherit commands, configuration, and items from existing omnibars:
166
+
167
+ ```ruby
168
+ SuperuserOmnibar = Class.new(UserOmnibar).configure do |c|
169
+ # add more items that only superusers should get
170
+ end
147
171
  ```
148
172
 
149
173
  ### Other options and usage patterns
@@ -172,7 +196,7 @@ end
172
196
  ```ruby
173
197
  module AddOmnibar
174
198
  def build_page(...)
175
- within(super) { text_node(MyOmnibar.render) }
199
+ within(super) { text_node(MyOmnibar.render(self)) }
176
200
  end
177
201
  end
178
202
  ActiveAdmin::Views::Pages::Base.prepend(AddOmnibar)
@@ -180,7 +204,7 @@ ActiveAdmin::Views::Pages::Base.prepend(AddOmnibar)
180
204
 
181
205
  ##### To render in RailsAdmin
182
206
 
183
- Add `MyOmnibar.render` to `app/views/layouts/rails_admin/application.*`.
207
+ Add `MyOmnibar.render(self)` to `app/views/layouts/rails_admin/application.*`.
184
208
 
185
209
  #### Adding all index routes as searchable items
186
210
 
@@ -1,5 +1,5 @@
1
1
  class RailsOmnibar::HtmlController < RailsOmnibar::BaseController
2
2
  def show
3
- render html: omnibar.render
3
+ render html: omnibar.render(self)
4
4
  end
5
5
  end
data/bin/console CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'rails_omnibar'
5
+ require_relative '../spec/dummy/config/environment'
5
6
 
6
7
  require 'irb'
7
8
  IRB.start(__FILE__)
@@ -1,13 +1,14 @@
1
1
  class RailsOmnibar
2
2
  module Command
3
3
  class Base
4
- attr_reader :pattern, :resolver, :description, :example
4
+ attr_reader :pattern, :resolver, :description, :example, :if
5
5
 
6
- def initialize(pattern:, resolver:, description: nil, example: nil)
6
+ def initialize(pattern:, resolver:, description: nil, example: nil, if: nil)
7
7
  @pattern = cast_to_pattern(pattern)
8
8
  @resolver = RailsOmnibar.cast_to_proc(resolver)
9
9
  @description = description
10
10
  @example = example
11
+ @if = RailsOmnibar.cast_to_condition(binding.local_variable_get(:if))
11
12
  end
12
13
 
13
14
  def call(input, controller:, omnibar:)
@@ -19,6 +20,12 @@ class RailsOmnibar
19
20
  results.map { |e| RailsOmnibar.cast_to_item(e) }
20
21
  end
21
22
 
23
+ def handle?(input, controller:, omnibar:)
24
+ return false unless pattern.match?(input)
25
+
26
+ RailsOmnibar.evaluate_condition(self.if, context: controller, omnibar: omnibar)
27
+ end
28
+
22
29
  private
23
30
 
24
31
  def cast_to_pattern(arg)
@@ -29,7 +29,7 @@ class RailsOmnibar
29
29
 
30
30
  # ActiveRecord-specific search.
31
31
  class RecordSearch < Search
32
- def initialize(model:, columns: :id, pattern: nil, finder: nil, itemizer: nil, example: nil)
32
+ def initialize(model:, columns: :id, pattern: nil, finder: nil, itemizer: nil, example: nil, if: nil)
33
33
  # casting and validations
34
34
  model = model.to_s.classify.constantize unless model.is_a?(Class)
35
35
  model < ActiveRecord::Base || raise(ArgumentError, 'model: must be a model')
@@ -64,6 +64,7 @@ class RailsOmnibar
64
64
  pattern: pattern,
65
65
  finder: finder,
66
66
  itemizer: itemizer,
67
+ if: binding.local_variable_get(:if),
67
68
  )
68
69
  end
69
70
  end
@@ -1,17 +1,15 @@
1
1
  class RailsOmnibar
2
2
  def handle(input, controller)
3
- handler = commands.find { |h| h.pattern.match?(input) }
3
+ handler = commands.find do |cmd|
4
+ cmd.handle?(input, controller: controller, omnibar: self)
5
+ end
4
6
  handler&.call(input, controller: controller, omnibar: self) || []
5
7
  end
6
8
 
7
- def command_pattern
8
- commands.any? ? Regexp.union(commands.map(&:pattern)) : /$NO_COMMANDS/
9
- end
10
-
11
9
  def add_command(command)
12
- check_const_and_clear_cache
13
10
  commands << RailsOmnibar.cast_to_command(command)
14
- self
11
+ clear_command_pattern_cache
12
+ self.class
15
13
  end
16
14
 
17
15
  def self.cast_to_command(arg)
@@ -43,6 +41,17 @@ class RailsOmnibar
43
41
 
44
42
  private
45
43
 
44
+ def command_pattern
45
+ @command_pattern ||= begin
46
+ re = commands.any? ? Regexp.union(commands.map(&:pattern)) : /$NO_COMMANDS/
47
+ JsRegex.new!(re, target: 'ES2018')
48
+ end
49
+ end
50
+
51
+ def clear_command_pattern_cache
52
+ @command_pattern = nil
53
+ end
54
+
46
55
  def commands
47
56
  @commands ||= []
48
57
  end
@@ -0,0 +1,27 @@
1
+ class RailsOmnibar
2
+ def self.cast_to_condition(arg)
3
+ case arg
4
+ when nil, true, false then arg
5
+ else
6
+ arg.try(:arity) == 0 ? arg : RailsOmnibar.cast_to_proc(arg)
7
+ end
8
+ end
9
+
10
+ def self.evaluate_condition(condition, context:, omnibar:)
11
+ case condition
12
+ when nil, true then true
13
+ when false then false
14
+ else
15
+ context || raise(<<~EOS)
16
+ Missing context for condition, please render the omnibar with `.render(self)`
17
+ EOS
18
+ if condition.try(:arity) == 0
19
+ context.instance_exec(&condition)
20
+ elsif condition.respond_to?(:call)
21
+ condition.call(context, controller: context, omnibar: omnibar)
22
+ else
23
+ raise("unsupported condition type: #{condition.class}")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,12 +1,14 @@
1
1
  class RailsOmnibar
2
2
  def configure(&block)
3
- check_const_and_clear_cache
4
3
  tap(&block)
4
+ self.class
5
5
  end
6
6
 
7
- attr_reader :auth
8
7
  def auth=(arg)
9
- @auth = arg.try(:arity) == 0 ? arg : RailsOmnibar.cast_to_proc(arg)
8
+ config[:auth] = arg.try(:arity) == 0 ? arg : RailsOmnibar.cast_to_proc(arg)
9
+ end
10
+ def auth
11
+ config[:auth]
10
12
  end
11
13
  def authorize(controller)
12
14
  if auth.nil?
@@ -20,33 +22,39 @@ class RailsOmnibar
20
22
 
21
23
  def max_results=(arg)
22
24
  arg.is_a?(Integer) && arg > 0 || raise(ArgumentError, 'max_results must be > 0')
23
- @max_results = arg
25
+ config[:max_results] = arg
24
26
  end
25
27
  def max_results
26
- @max_results || 10
28
+ config[:max_results] || 10
27
29
  end
28
30
 
29
- attr_writer :modal
31
+ def modal=(arg)
32
+ config[:modal] = arg
33
+ end
30
34
  def modal?
31
- instance_variable_defined?(:@modal) ? !!@modal : false
35
+ config.key?(:modal) ? !!config[:modal] : false
32
36
  end
33
37
 
34
- attr_writer :calculator
38
+ def calculator=(arg)
39
+ config[:calculator] = arg
40
+ end
35
41
  def calculator?
36
- instance_variable_defined?(:@calculator) ? !!@calculator : true
42
+ config.key?(:calculator) ? !!config[:calculator] : true
37
43
  end
38
44
 
39
- def hotkey
40
- @hotkey || 'k'
41
- end
42
45
  def hotkey=(arg)
43
46
  arg.to_s.size == 1 || raise(ArgumentError, 'hotkey must have length 1')
44
- @hotkey = arg.to_s.downcase
47
+ config[:hotkey] = arg.to_s.downcase
48
+ end
49
+ def hotkey
50
+ config[:hotkey] || 'k'
45
51
  end
46
52
 
47
- attr_writer :placeholder
53
+ def placeholder=(arg)
54
+ config[:placeholder] = arg
55
+ end
48
56
  def placeholder
49
- return @placeholder.presence unless @placeholder.nil?
57
+ return config[:placeholder].presence unless config[:placeholder].nil?
50
58
 
51
59
  help_item = items.find { |i| i.type == :help }
52
60
  help_item && "Hint: Type `#{help_item.title}` for help"
@@ -54,13 +62,15 @@ class RailsOmnibar
54
62
 
55
63
  private
56
64
 
65
+ def config
66
+ @config ||= {}
67
+ end
68
+
57
69
  def omnibar_class
58
70
  self.class.name || raise(<<~EOS)
59
- RailsOmnibar subclasses must be assigned to constants
60
- before configuring or rendering them. E.g.:
71
+ RailsOmnibar subclasses must be assigned to constants, e.g.:
61
72
 
62
- Foo = Class.new(RailsOmnibar)
63
- Foo.configure { ... }
73
+ Foo = Class.new(RailsOmnibar).configure { ... }
64
74
  EOS
65
75
  end
66
76
  end
@@ -0,0 +1,9 @@
1
+ class RailsOmnibar
2
+ def self.inherited(subclass)
3
+ bar1 = singleton
4
+ bar2 = subclass.send(:singleton)
5
+ %i[@commands @config @items].each do |ivar|
6
+ bar2.instance_variable_set(ivar, bar1.instance_variable_get(ivar).dup)
7
+ end
8
+ end
9
+ end
@@ -1,9 +1,9 @@
1
1
  class RailsOmnibar
2
2
  module Item
3
3
  class Base
4
- attr_reader :title, :url, :icon, :modal_html, :suggested, :type
4
+ attr_reader :title, :url, :icon, :modal_html, :suggested, :type, :if
5
5
 
6
- def initialize(title:, url: nil, icon: nil, modal_html: nil, suggested: false, type: :default)
6
+ def initialize(title:, url: nil, icon: nil, modal_html: nil, suggested: false, type: :default, if: nil)
7
7
  url.present? && modal_html.present? && raise(ArgumentError, 'use EITHER url: OR modal_html:')
8
8
 
9
9
  @title = validate_title(title)
@@ -12,10 +12,16 @@ class RailsOmnibar
12
12
  @modal_html = modal_html
13
13
  @suggested = !!suggested
14
14
  @type = type
15
+ @if = RailsOmnibar.cast_to_condition(binding.local_variable_get(:if))
15
16
  end
16
17
 
17
18
  def as_json(*)
18
- { title: title, url: url, icon: icon, modalHTML: modal_html, suggested: suggested, type: type }
19
+ @as_json ||=
20
+ { title: title, url: url, icon: icon, modalHTML: modal_html, suggested: suggested, type: type }
21
+ end
22
+
23
+ def render?(context:, omnibar:)
24
+ RailsOmnibar.evaluate_condition(self.if, context: context, omnibar: omnibar)
19
25
  end
20
26
 
21
27
  private
@@ -1,13 +1,12 @@
1
1
  class RailsOmnibar
2
2
  def add_item(item)
3
- check_const_and_clear_cache
4
3
  items << RailsOmnibar.cast_to_item(item)
5
- self
4
+ self.class
6
5
  end
7
6
 
8
7
  def add_items(*args)
9
8
  args.each { |arg| add_item(arg) }
10
- self
9
+ self.class
11
10
  end
12
11
 
13
12
  def self.cast_to_item(arg)
@@ -1,6 +1,7 @@
1
1
  class RailsOmnibar
2
- def render
3
- @cached_html ||= <<~HTML.html_safe
2
+ def render(context = nil)
3
+ @context = context
4
+ <<~HTML.html_safe
4
5
  <script src='#{urls.js_path}?v=#{RailsOmnibar::VERSION}' type='text/javascript'></script>
5
6
  <div id='mount-rails-omnibar'>
6
7
  <script type="application/json">#{to_json}</script>
@@ -17,9 +18,9 @@ class RailsOmnibar
17
18
  def as_json(*)
18
19
  {
19
20
  calculator: calculator?,
20
- commandPattern: JsRegex.new!(command_pattern, target: 'ES2018'),
21
+ commandPattern: command_pattern,
21
22
  hotkey: hotkey,
22
- items: items,
23
+ items: items.select { |i| i.render?(context: @context, omnibar: self) },
23
24
  maxResults: max_results,
24
25
  modal: modal?,
25
26
  placeholder: placeholder,
@@ -30,11 +31,4 @@ class RailsOmnibar
30
31
  def urls
31
32
  @urls ||= RailsOmnibar::Engine.routes.url_helpers
32
33
  end
33
-
34
- private
35
-
36
- def check_const_and_clear_cache
37
- omnibar_class # trigger constant assignment check
38
- @cached_html = nil
39
- end
40
34
  end
@@ -1,3 +1,3 @@
1
1
  class RailsOmnibar
2
- VERSION = '1.6.0'
2
+ VERSION = '1.7.0'
3
3
  end
@@ -0,0 +1,16 @@
1
+ require_relative '../rails_helper'
2
+ require 'bundler/inline'
3
+
4
+ gemfile do
5
+ source 'https://rubygems.org'
6
+ gem 'benchmark-ips', require: 'benchmark/ips'
7
+ end
8
+
9
+ BenchmarkBar = Class.new(RailsOmnibar).configure do |c|
10
+ 100.times { c.add_item(title: rand.to_s, url: rand.to_s) }
11
+ 10.times { c.add_command(description: rand.to_s, pattern: /#{rand}/, example: rand.to_s, resolver: ->(_){}) }
12
+ end
13
+
14
+ Benchmark.ips do |x|
15
+ x.report('render') { BenchmarkBar.render } # ~3k ips
16
+ end
@@ -53,10 +53,8 @@ describe RailsOmnibar do
53
53
  expect(subject.placeholder).to eq nil
54
54
  end
55
55
 
56
- it 'raises when trying to configure or render from an anonymous class' do
56
+ it 'raises when trying to render from an anonymous class' do
57
57
  klass = Class.new(RailsOmnibar)
58
- expect { klass.configure {} }.to raise_error(/constant/)
59
- expect { klass.add_item(title: 'a', url: 'b') }.to raise_error(/constant/)
60
58
  expect { klass.render }.to raise_error(/constant/)
61
59
  end
62
60
  end
@@ -0,0 +1,79 @@
1
+ require 'rails_helper'
2
+
3
+ describe RailsOmnibar do
4
+ it 'inherits commands from a parent class' do
5
+ bar1 = Class.new(RailsOmnibar).configure do |c|
6
+ c.add_command(pattern: /foo1/, resolver: ->(_){})
7
+ end
8
+ bar2 = Class.new(bar1).configure do |c|
9
+ c.add_command(pattern: /foo2/, resolver: ->(_){})
10
+ end
11
+ bar3 = Class.new(bar2).configure do |c|
12
+ c.add_command(pattern: /foo3/, resolver: ->(_){})
13
+ end
14
+
15
+ commands = ->(bar) do
16
+ bar.send(:singleton).send(:commands).map { |c| c.pattern.source }
17
+ end
18
+
19
+ expect(commands.call(bar1)).to eq ['foo1']
20
+ expect(commands.call(bar2)).to eq ['foo1', 'foo2']
21
+ expect(commands.call(bar3)).to eq ['foo1', 'foo2', 'foo3']
22
+
23
+ # later changes to commands should not affect child classes
24
+ bar1.add_command(pattern: /foo1B/, resolver: ->(_){})
25
+ expect(commands.call(bar1)).to eq ['foo1', 'foo1B']
26
+ expect(commands.call(bar2)).to eq ['foo1', 'foo2']
27
+ expect(commands.call(bar3)).to eq ['foo1', 'foo2', 'foo3']
28
+ end
29
+
30
+ it 'inherits configuration from a parent class' do
31
+ bar1 = Class.new(RailsOmnibar).configure do |c|
32
+ c.max_results = 7
33
+ c.placeholder = 'hi'
34
+ c.hotkey = 'j'
35
+ end
36
+ bar2 = Class.new(bar1).configure do |c|
37
+ c.max_results = 8
38
+ end
39
+ bar3 = Class.new(bar2).configure do |c|
40
+ c.hotkey = 'k'
41
+ end
42
+
43
+ config = ->(bar) { bar.send(:singleton).send(:config) }
44
+
45
+ expect(config.call(bar1)).to eq(max_results: 7, placeholder: 'hi', hotkey: 'j')
46
+ expect(config.call(bar2)).to eq(max_results: 8, placeholder: 'hi', hotkey: 'j')
47
+ expect(config.call(bar3)).to eq(max_results: 8, placeholder: 'hi', hotkey: 'k')
48
+
49
+ # later changes to config should not affect child classes
50
+ bar1.placeholder = 'bye'
51
+ expect(bar1.placeholder).to eq 'bye'
52
+ expect(bar2.placeholder).to eq 'hi'
53
+ expect(bar3.placeholder).to eq 'hi'
54
+ end
55
+
56
+ it 'inherits items from a parent class' do
57
+ bar1 = Class.new(RailsOmnibar).configure do |c|
58
+ c.add_item(title: 'foo1', url: 'bar1')
59
+ end
60
+ bar2 = Class.new(bar1).configure do |c|
61
+ c.add_item(title: 'foo2', url: 'bar2')
62
+ end
63
+ bar3 = Class.new(bar2).configure do |c|
64
+ c.add_item(title: 'foo3', url: 'bar3')
65
+ end
66
+
67
+ items = ->(bar) { bar.send(:singleton).send(:items).map(&:title) }
68
+
69
+ expect(items.call(bar1)).to eq ['foo1']
70
+ expect(items.call(bar2)).to eq ['foo1', 'foo2']
71
+ expect(items.call(bar3)).to eq ['foo1', 'foo2', 'foo3']
72
+
73
+ # later changes to items should not affect child classes
74
+ bar1.add_item(title: 'foo1B', url: 'bar1B')
75
+ expect(items.call(bar1)).to eq ['foo1', 'foo1B']
76
+ expect(items.call(bar2)).to eq ['foo1', 'foo2']
77
+ expect(items.call(bar3)).to eq ['foo1', 'foo2', 'foo3']
78
+ end
79
+ end
@@ -119,6 +119,33 @@ describe RailsOmnibar do
119
119
  expect(page).not_to have_content 'fake_result_1'
120
120
  end
121
121
 
122
+ it 'can have conditional items and commands' do
123
+ visit main_app.root_path
124
+ send_keys([:control, 'm']) # custom hotkey, c.f. my_omnibar_template.rb
125
+ expect(page).to have_selector 'input'
126
+
127
+ type('condi')
128
+ expect(page).not_to have_content 'conditional item'
129
+
130
+ FactoryBot.create(:user)
131
+ expect { type('DELETE users'); sleep 0.3 }.not_to change { User.count }
132
+
133
+ # now again with truthy condition
134
+ ENV['FAKE_OMNIBAR_IF'] = '1'
135
+ refresh # reload page
136
+
137
+ send_keys([:control, 'm']) # custom hotkey, c.f. my_omnibar_template.rb
138
+ expect(page).to have_selector 'input'
139
+
140
+ type('condi')
141
+ expect(page).to have_content 'conditional item'
142
+
143
+ FactoryBot.create(:user)
144
+ expect { type('DELETE users'); sleep 0.3 }.to change { User.count }.to(0)
145
+ ensure
146
+ ENV['FAKE_OMNIBAR_IF'] = nil
147
+ end
148
+
122
149
  def type(str)
123
150
  find('input').set(str)
124
151
  end
@@ -29,7 +29,7 @@ file 'app/lib/aa/users.rb', File.read(__dir__ + '/user_resource_template.rb
29
29
 
30
30
  inject_into_class 'app/controllers/application_controller.rb', 'ApplicationController', <<-RUBY
31
31
  def index
32
- render html: (MyOmnibar.render + OtherOmnibar.render)
32
+ render html: (MyOmnibar.render(self) + OtherOmnibar.render(self))
33
33
  end
34
34
  RUBY
35
35
 
@@ -3,6 +3,7 @@ MyOmnibar = RailsOmnibar.configure do |c|
3
3
 
4
4
  c.add_item(title: 'important URL', url: 'https://www.disney.com', suggested: true)
5
5
  c.add_item(title: 'boring URL', url: 'https://www.github.com')
6
+ c.add_item(title: 'conditional item', url: '#', if: -> { ENV['FAKE_OMNIBAR_IF'] })
6
7
 
7
8
  c.add_webadmin_items(prefix: 'Admin:')
8
9
 
@@ -43,6 +44,13 @@ MyOmnibar = RailsOmnibar.configure do |c|
43
44
  end,
44
45
  )
45
46
 
47
+ c.add_command(
48
+ description: 'Delete users',
49
+ pattern: /DELETE (.+)/i,
50
+ resolver: ->(value){ { title: value.classify.constantize.delete_all.to_s } },
51
+ if: ->{ ENV['FAKE_OMNIBAR_IF'] },
52
+ )
53
+
46
54
  c.add_help
47
55
 
48
56
  # Use a hotkey that is the same in most keyboard layouts to work around
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_omnibar
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janosch Müller
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-01-25 00:00:00.000000000 Z
10
+ date: 2024-07-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: js_regex
@@ -45,7 +44,6 @@ dependencies:
45
44
  - !ruby/object:Gem::Version
46
45
  version: '8.0'
47
46
  description: Omnibar for Rails
48
- email:
49
47
  executables: []
50
48
  extensions: []
51
49
  extra_rdoc_files: []
@@ -79,8 +77,10 @@ files:
79
77
  - lib/rails_omnibar/command/base.rb
80
78
  - lib/rails_omnibar/command/search.rb
81
79
  - lib/rails_omnibar/commands.rb
80
+ - lib/rails_omnibar/conditions.rb
82
81
  - lib/rails_omnibar/config.rb
83
82
  - lib/rails_omnibar/engine.rb
83
+ - lib/rails_omnibar/inheritance.rb
84
84
  - lib/rails_omnibar/item/base.rb
85
85
  - lib/rails_omnibar/item/help.rb
86
86
  - lib/rails_omnibar/item/webadmin.rb
@@ -89,7 +89,9 @@ files:
89
89
  - lib/rails_omnibar/version.rb
90
90
  - package.json
91
91
  - rails_omnibar.gemspec
92
+ - spec/benchmarks/benchmark.rb
92
93
  - spec/lib/rails_omnibar/config_spec.rb
94
+ - spec/lib/rails_omnibar/inheritance_spec.rb
93
95
  - spec/lib/rails_omnibar/item/base_spec.rb
94
96
  - spec/lib/rails_omnibar/version_spec.rb
95
97
  - spec/rails_helper.rb
@@ -105,7 +107,6 @@ homepage: https://github.com/jaynetics/rails_omnibar
105
107
  licenses:
106
108
  - MIT
107
109
  metadata: {}
108
- post_install_message:
109
110
  rdoc_options: []
110
111
  require_paths:
111
112
  - lib
@@ -120,12 +121,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
121
  - !ruby/object:Gem::Version
121
122
  version: '0'
122
123
  requirements: []
123
- rubygems_version: 3.5.0.dev
124
- signing_key:
124
+ rubygems_version: 3.6.0.dev
125
125
  specification_version: 4
126
126
  summary: Omnibar for Rails
127
127
  test_files:
128
+ - spec/benchmarks/benchmark.rb
128
129
  - spec/lib/rails_omnibar/config_spec.rb
130
+ - spec/lib/rails_omnibar/inheritance_spec.rb
129
131
  - spec/lib/rails_omnibar/item/base_spec.rb
130
132
  - spec/lib/rails_omnibar/version_spec.rb
131
133
  - spec/rails_helper.rb