flipper-ui 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d6bef28ffc3f333f954329fb96d70f3b67709357f3d0409f754dc29203516ce
4
- data.tar.gz: d9c361816a630c01cb46fc3a8bfddd6ebacea70785a400a60e28df16aed7b2f7
3
+ metadata.gz: be9d4667f30e16f2d6f4ccb72bbb3e3f46b7c0261274bea9ec2e31fa0c403210
4
+ data.tar.gz: '09bb8b603b54d6c4161f312b4ba0be1ac92299d0b55c29f21b5fdd5961034a0d'
5
5
  SHA512:
6
- metadata.gz: f161c4792bd93d5686ee2ee4d4ec1beaba76a6f01009c0d323a5b2d0128b02cc14924ed2a3b30c4997a1eb841fa9e9fb72e3470c63bbc958567a837e9e429d74
7
- data.tar.gz: a6065032596e01620d8f249dc4434767e399ad7ed1ae582a70f11feab86dc21d0846c0b6d98313948485faf7303ee758c62de944de25998c5675e400f02c6b38
6
+ metadata.gz: a15b882c1e7a5248da12a71f7dd4c9df7f9d63a72cccad36efc7d64cd4b88280eaff9cf0999d3737eab2d7bd4745ee926fcc1cf59cd1f060944636264ff37202
7
+ data.tar.gz: baad050fea403866a36c3cba1520d0e1a9e8224a80f5d97c478bc098c583a66ce29cb35f99f6b21d2caebf48d84fa0e62629a36fafc2724d51dc5d5d7aa784b2
data/flipper-ui.gemspec CHANGED
@@ -25,5 +25,5 @@ Gem::Specification.new do |gem|
25
25
  gem.add_dependency 'rack-session', '>= 1.0.2', '< 3.0.0'
26
26
  gem.add_dependency 'flipper', "~> #{Flipper::VERSION}"
27
27
  gem.add_dependency 'erubi', '>= 1.0.0', '< 2.0.0'
28
- gem.add_dependency 'sanitize', '< 7'
28
+ gem.add_dependency 'sanitize', '< 8'
29
29
  end
@@ -12,7 +12,7 @@ module Flipper
12
12
  def feature_name
13
13
  @feature_name ||= begin
14
14
  match = request.path_info.match(self.class.route_regex)
15
- match ? Rack::Utils.unescape(match[:feature_name]) : nil
15
+ match ? Flipper::UI::Util.unescape(match[:feature_name]) : nil
16
16
  end
17
17
  end
18
18
  private :feature_name
@@ -164,7 +164,7 @@ module Flipper
164
164
  # location - The String location to set the Location header to.
165
165
  def redirect_to(location)
166
166
  status 302
167
- header 'location', "#{script_name}#{Rack::Utils.escape_path(location)}"
167
+ header 'location', "#{script_name}#{location}"
168
168
  halt [@code, @headers, ['']]
169
169
  end
170
170
 
@@ -25,7 +25,7 @@ module Flipper
25
25
 
26
26
  if values.empty?
27
27
  error = "#{value.inspect} is not a valid actor value."
28
- redirect_to("/features/#{feature.key}/actors?error=#{error}")
28
+ redirect_to("/features/#{Flipper::UI::Util.escape feature.key}/actors?error=#{Flipper::UI::Util.escape error}")
29
29
  end
30
30
 
31
31
  values.each do |value|
@@ -39,7 +39,7 @@ module Flipper
39
39
  end
40
40
  end
41
41
 
42
- redirect_to("/features/#{feature.key}")
42
+ redirect_to("/features/#{Flipper::UI::Util.escape feature.key}")
43
43
  end
44
44
  end
45
45
  end
@@ -21,7 +21,7 @@ module Flipper
21
21
  feature.disable
22
22
  end
23
23
 
24
- redirect_to "/features/#{@feature.key}"
24
+ redirect_to "/features/#{Flipper::UI::Util.escape @feature.key}"
25
25
  end
26
26
  end
27
27
  end
@@ -45,13 +45,13 @@ module Flipper
45
45
 
46
46
  if Util.blank?(value)
47
47
  error = "#{value.inspect} is not a valid feature name."
48
- redirect_to("/features/new?error=#{error}")
48
+ redirect_to("/features/new?error=#{Flipper::UI::Util.escape error}")
49
49
  end
50
50
 
51
51
  feature = flipper[value]
52
52
  feature.add
53
53
 
54
- redirect_to "/features/#{value}"
54
+ redirect_to "/features/#{Flipper::UI::Util.escape value}"
55
55
  end
56
56
  end
57
57
  end
@@ -30,10 +30,10 @@ module Flipper
30
30
  feature.disable_group value
31
31
  end
32
32
 
33
- redirect_to("/features/#{feature.key}")
33
+ redirect_to("/features/#{Flipper::UI::Util.escape feature.key}")
34
34
  else
35
35
  error = "The group named #{value.inspect} has not been registered."
36
- redirect_to("/features/#{feature.key}/groups?error=#{error}")
36
+ redirect_to("/features/#{Flipper::UI::Util.escape feature.key}/groups?error=#{Flipper::UI::Util.escape error}")
37
37
  end
38
38
  end
39
39
  end
@@ -19,10 +19,10 @@ module Flipper
19
19
  feature.enable_percentage_of_actors params['value']
20
20
  rescue ArgumentError => exception
21
21
  error = "Invalid percentage of actors value: #{exception.message}"
22
- redirect_to("/features/#{@feature.key}?error=#{error}")
22
+ redirect_to("/features/#{Flipper::UI::Util.escape @feature.key}?error=#{Flipper::UI::Util.escape error}")
23
23
  end
24
24
 
25
- redirect_to "/features/#{@feature.key}"
25
+ redirect_to "/features/#{Flipper::UI::Util.escape @feature.key}"
26
26
  end
27
27
  end
28
28
  end
@@ -19,10 +19,10 @@ module Flipper
19
19
  feature.enable_percentage_of_time params['value']
20
20
  rescue ArgumentError => exception
21
21
  error = "Invalid percentage of time value: #{exception.message}"
22
- redirect_to("/features/#{@feature.key}?error=#{error}")
22
+ redirect_to("/features/#{Flipper::UI::Util.escape @feature.key}?error=#{Flipper::UI::Util.escape error}")
23
23
  end
24
24
 
25
- redirect_to "/features/#{@feature.key}"
25
+ redirect_to "/features/#{Flipper::UI::Util.escape @feature.key}"
26
26
  end
27
27
  end
28
28
  end
@@ -5,8 +5,8 @@ module Flipper
5
5
  class Configuration
6
6
  attr_reader :delete
7
7
 
8
- attr_accessor :banner_text,
9
- :banner_class
8
+ attr_accessor :banner_text
9
+ attr_reader :banner_class
10
10
 
11
11
  # Public: Is the UI in read only mode or not. Default is false. This
12
12
  # supersedes all other write-related options such as
@@ -1,9 +1,19 @@
1
+ require "rack/utils"
2
+
1
3
  module Flipper
2
4
  module UI
3
5
  module Util
4
6
  # Private: 0x3000: fullwidth whitespace
5
7
  NON_WHITESPACE_REGEXP = /[^\s#{[0x3000].pack("U")}]/
6
8
 
9
+ def self.escape(str)
10
+ Rack::Utils.escape(str)
11
+ end
12
+
13
+ def self.unescape(str)
14
+ Rack::Utils.unescape(str)
15
+ end
16
+
7
17
  def self.blank?(str)
8
18
  str.to_s !~ NON_WHITESPACE_REGEXP
9
19
  end
@@ -6,7 +6,7 @@
6
6
 
7
7
  <div class="card">
8
8
  <h4 class="card-header">
9
- <a class="link-dark" href="<%= script_name %>/features/<%= @feature.key %>"><%= @feature.key %></a>
9
+ <a class="link-dark" href="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>"><%= @feature.key %></a>
10
10
  /
11
11
  Enable Actor
12
12
  </h4>
@@ -14,7 +14,7 @@
14
14
  <p>
15
15
  Turn on this feature for actors.
16
16
  </p>
17
- <form action="<%= script_name %>/features/<%= @feature.key %>/actors" method="post" class="row">
17
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/actors" method="post" class="row">
18
18
  <%== csrf_input_tag %>
19
19
  <input type="hidden" name="operation" value="enable">
20
20
  <div class="col"><input type="text" name="value" placeholder="<%= Flipper::UI.configuration.add_actor_placeholder %>" class="form-control"></div>
@@ -6,7 +6,7 @@
6
6
 
7
7
  <div class="card">
8
8
  <h4 class="card-header">
9
- <a class="link-dark" href="<%= script_name %>/features/<%= @feature.key %>"><%= @feature.key %></a>
9
+ <a class="link-dark" href="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>"><%= @feature.key %></a>
10
10
  /
11
11
  Enable Group</h4>
12
12
  <div class="card-body">
@@ -16,7 +16,7 @@
16
16
  <p>
17
17
  Turn on this feature for an entire group of actors.
18
18
  </p>
19
- <form action="<%= script_name %>/features/<%= @feature.key %>/groups" method="post" class="row">
19
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/groups" method="post" class="row">
20
20
  <%== csrf_input_tag %>
21
21
  <input type="hidden" name="operation" value="enable">
22
22
  <div class="col">
@@ -50,7 +50,7 @@
50
50
  <button class="btn btn-outline-secondary js-toggle-trigger" data-bs-toggle="collapse" data-bs-target="#add-actor">Add an actor</button>
51
51
  </div>
52
52
  <div class="col toggle-block-when-on">
53
- <form action="<%= script_name %>/features/<%= @feature.key %>/actors" method="post" class="row">
53
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/actors" method="post" class="row">
54
54
  <%== csrf_input_tag %>
55
55
  <input type="hidden" name="operation" value="enable">
56
56
  <div class="col">
@@ -83,7 +83,7 @@
83
83
  </div>
84
84
  <div class="col col-auto">
85
85
  <% if write_allowed? %>
86
- <form action="<%= script_name %>/features/<%= @feature.key %>/actors" method="post">
86
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/actors" method="post">
87
87
  <%== csrf_input_tag %>
88
88
  <input type="hidden" name="operation" value="disable">
89
89
  <input type="hidden" name="value" value="<%= item %>">
@@ -119,7 +119,7 @@
119
119
  <% if @feature.disabled_groups.empty? %>
120
120
  All groups enabled.
121
121
  <% else %>
122
- <form action="<%= script_name %>/features/<%= @feature.key %>/groups" method="post" class="row">
122
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/groups" method="post" class="row">
123
123
  <%== csrf_input_tag %>
124
124
  <input type="hidden" name="operation" value="enable">
125
125
  <div class="col">
@@ -150,7 +150,7 @@
150
150
  </div>
151
151
  <div class="col col-auto">
152
152
  <% if write_allowed? %>
153
- <form action="<%= script_name %>/features/<%= @feature.key %>/groups" method="post">
153
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/groups" method="post">
154
154
  <%== csrf_input_tag %>
155
155
  <input type="hidden" name="operation" value="disable">
156
156
  <input type="hidden" name="value" value="<%= item %>">
@@ -185,7 +185,7 @@
185
185
  <% if write_allowed? %>
186
186
  <div class="card-body border-bottom toggle-block-when-on bg-lightest">
187
187
  <div class="row align-items-center">
188
- <form action="<%= script_name %>/features/<%= @feature.key %>/percentage_of_actors" method="post" class="col">
188
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/percentage_of_actors" method="post" class="col">
189
189
  <%== csrf_input_tag %>
190
190
  <div class="btn-group">
191
191
  <% @percentages.each do |number| %>
@@ -193,7 +193,7 @@
193
193
  <% end %>
194
194
  </div>
195
195
  </form>
196
- <form action="<%= script_name %>/features/<%= @feature.key %>/percentage_of_actors" method="post" class="col-auto row">
196
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/percentage_of_actors" method="post" class="col-auto row">
197
197
  <%== csrf_input_tag %>
198
198
  <div class="col-auto">
199
199
  <input style="width:5em;" type="number" max="100" min="0" name="value" <% if @feature.percentage_of_actors_value > 0 %>value="<%= @feature.percentage_of_actors_value %>"<% end %> title="Custom percentage (26, 32, etc.)" placeholder="0" class="form-control">
@@ -226,7 +226,7 @@
226
226
  <% if write_allowed? %>
227
227
  <div class="card-body border-bottom toggle-block-when-on bg-lightest">
228
228
  <div class="row align-items-center">
229
- <form action="<%= script_name %>/features/<%= @feature.key %>/percentage_of_time" method="post" class="col">
229
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/percentage_of_time" method="post" class="col">
230
230
  <%== csrf_input_tag %>
231
231
  <div class="btn-group">
232
232
  <% @percentages.each do |number| %>
@@ -234,7 +234,7 @@
234
234
  <% end %>
235
235
  </div>
236
236
  </form>
237
- <form action="<%= script_name %>/features/<%= @feature.key %>/percentage_of_time" method="post" class="col-auto row">
237
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/percentage_of_time" method="post" class="col-auto row">
238
238
  <%== csrf_input_tag %>
239
239
  <div class="col-auto">
240
240
  <input style="width:5em;" type="number" max="100" min="0" name="value" <% if @feature.percentage_of_time_value > 0 %>value="<%= @feature.percentage_of_time_value %>"<% end %> title="Custom percentage (26, 32, etc.)" placeholder="0" class="form-control">
@@ -249,7 +249,7 @@
249
249
 
250
250
  <% if write_allowed? %>
251
251
  <div class="card-body">
252
- <form action="<%= script_name %>/features/<%= @feature.key %>/boolean" method="post">
252
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>/boolean" method="post">
253
253
  <%== csrf_input_tag %>
254
254
 
255
255
  <div class="row">
@@ -301,7 +301,7 @@
301
301
  <p>
302
302
  <%= Flipper::UI.configuration.delete.description %>
303
303
  </p>
304
- <form action="<%= script_name %>/features/<%= @feature.key %>" method="post">
304
+ <form action="<%= script_name %>/features/<%= Flipper::UI::Util.escape @feature.key %>" method="post">
305
305
  <%== csrf_input_tag %>
306
306
  <input type="hidden" id="feature_name" name="_feature" value="<%= feature_name %>">
307
307
  <input type="hidden" name="_method" value="DELETE">
@@ -36,7 +36,7 @@
36
36
  </div>
37
37
  </div>
38
38
  <% @features.each do |feature| %>
39
- <a href="<%= "#{script_name}/features/#{feature.key}" %>" class="list-group-item list-group-item-action">
39
+ <a href="<%= "#{script_name}/features/#{Flipper::UI::Util.escape(feature.key)}" %>" class="list-group-item list-group-item-action">
40
40
  <div class="row align-items-center">
41
41
  <div class="col-1 text-center">
42
42
  <span class="status <%= feature.color_class %>" data-bs-toggle="tooltip" title=<%= feature.state.to_s.capitalize %>></span>
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <title><%= @page_title ? "#{@page_title} // " : "" %>Flipper</title>
4
+ <title><%= defined?(@page_title) ? "#{@page_title} // " : "" %>Flipper</title>
5
5
  <meta charset="utf-8">
6
6
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1">
data/lib/flipper/ui.rb CHANGED
@@ -20,12 +20,17 @@ module Flipper
20
20
 
21
21
  def self.app(flipper = nil, options = {})
22
22
  env_key = options.fetch(:env_key, 'flipper')
23
- rack_protection_options = options.fetch(:rack_protection, use: :authenticity_token)
23
+
24
+ if options.key?(:rack_protection)
25
+ warn "[DEPRECATION] `rack_protection` option is deprecated. " +
26
+ "Flipper::UI now only includes Rack::Protection::AuthenticityToken middleware. " +
27
+ "If you need additional protection, you can add it yourself."
28
+ end
24
29
 
25
30
  app = ->(_) { [200, { Rack::CONTENT_TYPE => 'text/html' }, ['']] }
26
31
  builder = Rack::Builder.new
27
32
  yield builder if block_given?
28
- builder.use Rack::Protection, rack_protection_options
33
+ builder.use Rack::Protection::AuthenticityToken
29
34
  builder.use Rack::MethodOverride
30
35
  builder.use Flipper::Middleware::SetupEnv, flipper, env_key: env_key
31
36
  builder.use Flipper::UI::Middleware, flipper: flipper, env_key: env_key
@@ -1,5 +1,5 @@
1
1
  module Flipper
2
- VERSION = '1.3.2'.freeze
2
+ VERSION = '1.3.3'.freeze
3
3
 
4
4
  REQUIRED_RUBY_VERSION = '2.6'.freeze
5
5
  NEXT_REQUIRED_RUBY_VERSION = '3.0'.freeze
@@ -35,7 +35,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
35
35
  end
36
36
 
37
37
  it 'renders add new actor form' do
38
- form = '<form action="/features/a/b/actors" method="post" class="row">'
38
+ form = '<form action="/features/a%2Fb/actors" method="post" class="row">'
39
39
  expect(last_response.body).to include(form)
40
40
  end
41
41
  end
@@ -73,7 +73,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
73
73
 
74
74
  context "when feature name contains space" do
75
75
  before do
76
- post 'features/sp%20ace/actors',
76
+ post 'features/sp+ace/actors',
77
77
  { 'value' => value, 'operation' => 'enable', 'authenticity_token' => token },
78
78
  'rack.session' => session
79
79
  end
@@ -84,7 +84,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
84
84
 
85
85
  it "redirects back to feature" do
86
86
  expect(last_response.status).to be(302)
87
- expect(last_response.headers['location']).to eq('/features/sp%20ace')
87
+ expect(last_response.headers['location']).to eq('/features/sp+ace')
88
88
  end
89
89
  end
90
90
 
@@ -114,7 +114,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
114
114
 
115
115
  it 'redirects back to feature' do
116
116
  expect(last_response.status).to be(302)
117
- expect(last_response.headers['location']).to eq('/features/search/actors?error=%22%22%20is%20not%20a%20valid%20actor%20value.')
117
+ expect(last_response.headers['location']).to eq('/features/search/actors?error=%22%22+is+not+a+valid+actor+value.')
118
118
  end
119
119
  end
120
120
 
@@ -123,7 +123,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
123
123
 
124
124
  it 'redirects back to feature' do
125
125
  expect(last_response.status).to be(302)
126
- expect(last_response.headers['location']).to eq('/features/search/actors?error=%22%22%20is%20not%20a%20valid%20actor%20value.')
126
+ expect(last_response.headers['location']).to eq('/features/search/actors?error=%22%22+is+not+a+valid+actor+value.')
127
127
  end
128
128
  end
129
129
  end
@@ -43,7 +43,7 @@ RSpec.describe Flipper::UI::Actions::BooleanGate do
43
43
 
44
44
  it 'redirects back to feature' do
45
45
  expect(last_response.status).to be(302)
46
- expect(last_response.headers['location']).to eq('/features/sp%20ace')
46
+ expect(last_response.headers['location']).to eq('/features/sp+ace')
47
47
  end
48
48
  end
49
49
 
@@ -197,4 +197,18 @@ RSpec.describe Flipper::UI::Actions::Feature do
197
197
  expect(last_response.body).to include('a/b')
198
198
  end
199
199
  end
200
+
201
+ describe 'GET /features/:feature with dot dot slash repeated in feature name' do
202
+ before do
203
+ get '/features/..%2F..%2F..%2F..%2Fblah'
204
+ end
205
+
206
+ it 'responds with success' do
207
+ expect(last_response.status).to be(200)
208
+ end
209
+
210
+ it 'renders template' do
211
+ expect(last_response.body).to include('../../../../blah')
212
+ end
213
+ end
200
214
  end
@@ -28,6 +28,16 @@ RSpec.describe Flipper::UI::Actions::Features do
28
28
  end
29
29
  end
30
30
 
31
+ it "escapes keys that are junky" do
32
+ flipper.add("../../../../blah")
33
+ flipper.add("this that")
34
+ flipper.add("foo/bar")
35
+ get '/features'
36
+ expect(last_response.body).to include("..%2F..%2F..%2F..%2Fblah")
37
+ expect(last_response.body).to include("this+that")
38
+ expect(last_response.body).to include("foo%2Fbar")
39
+ end
40
+
31
41
  context "when there are no features to list" do
32
42
  before do
33
43
  @original_fun_enabled = Flipper::UI.configuration.fun
@@ -124,7 +134,20 @@ RSpec.describe Flipper::UI::Actions::Features do
124
134
 
125
135
  it 'redirects to feature' do
126
136
  expect(last_response.status).to be(302)
127
- expect(last_response.headers['location']).to eq('/features/notifications%20next')
137
+ expect(last_response.headers['location']).to eq('/features/notifications+next')
138
+ end
139
+ end
140
+
141
+ context 'feature name contains ../' do
142
+ let(:feature_name) { '../../../foo' }
143
+
144
+ it 'adds feature with space' do
145
+ expect(flipper.features.map(&:key)).to include(feature_name)
146
+ end
147
+
148
+ it 'redirects to feature' do
149
+ expect(last_response.status).to be(302)
150
+ expect(last_response.headers['location']).to eq('/features/..%2F..%2F..%2Ffoo')
128
151
  end
129
152
  end
130
153
 
@@ -138,7 +161,7 @@ RSpec.describe Flipper::UI::Actions::Features do
138
161
 
139
162
  it 'redirects back to feature' do
140
163
  expect(last_response.status).to be(302)
141
- expect(last_response.headers['location']).to eq('/features/new?error=%22%22%20is%20not%20a%20valid%20feature%20name.')
164
+ expect(last_response.headers['location']).to eq('/features/new?error=%22%22+is+not+a+valid+feature+name.')
142
165
  end
143
166
  end
144
167
 
@@ -151,7 +174,7 @@ RSpec.describe Flipper::UI::Actions::Features do
151
174
 
152
175
  it 'redirects back to feature' do
153
176
  expect(last_response.status).to be(302)
154
- expect(last_response.headers['location']).to eq('/features/new?error=%22%22%20is%20not%20a%20valid%20feature%20name.')
177
+ expect(last_response.headers['location']).to eq('/features/new?error=%22%22+is+not+a+valid+feature+name.')
155
178
  end
156
179
  end
157
180
  end
@@ -60,7 +60,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do
60
60
 
61
61
  context 'feature name contains space' do
62
62
  before do
63
- post 'features/sp%20ace/groups',
63
+ post 'features/sp+ace/groups',
64
64
  { 'value' => group_name, 'operation' => 'enable', 'authenticity_token' => token },
65
65
  'rack.session' => session
66
66
  end
@@ -71,7 +71,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do
71
71
 
72
72
  it 'redirects back to feature' do
73
73
  expect(last_response.status).to be(302)
74
- expect(last_response.headers['location']).to eq('/features/sp%20ace')
74
+ expect(last_response.headers['location']).to eq('/features/sp+ace')
75
75
  end
76
76
  end
77
77
 
@@ -89,7 +89,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do
89
89
 
90
90
  it 'redirects back to feature' do
91
91
  expect(last_response.status).to be(302)
92
- expect(last_response.headers['location']).to eq('/features/search/groups?error=The%20group%20named%20%22not_here%22%20has%20not%20been%20registered.')
92
+ expect(last_response.headers['location']).to eq('/features/search/groups?error=The+group+named+%22not_here%22+has+not+been+registered.')
93
93
  end
94
94
  end
95
95
 
@@ -98,7 +98,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do
98
98
 
99
99
  it 'redirects back to feature' do
100
100
  expect(last_response.status).to be(302)
101
- expect(last_response.headers['location']).to eq('/features/search/groups?error=The%20group%20named%20%22%22%20has%20not%20been%20registered.')
101
+ expect(last_response.headers['location']).to eq('/features/search/groups?error=The+group+named+%22%22+has+not+been+registered.')
102
102
  end
103
103
  end
104
104
 
@@ -107,7 +107,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do
107
107
 
108
108
  it 'redirects back to feature' do
109
109
  expect(last_response.status).to be(302)
110
- expect(last_response.headers['location']).to eq('/features/search/groups?error=The%20group%20named%20%22%22%20has%20not%20been%20registered.')
110
+ expect(last_response.headers['location']).to eq('/features/search/groups?error=The+group+named+%22%22+has+not+been+registered.')
111
111
  end
112
112
  end
113
113
  end
@@ -30,7 +30,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfActorsGate do
30
30
 
31
31
  context 'with space in feature name' do
32
32
  before do
33
- post 'features/sp%20ace/percentage_of_actors',
33
+ post 'features/sp+ace/percentage_of_actors',
34
34
  { 'value' => '24', 'authenticity_token' => token },
35
35
  'rack.session' => session
36
36
  end
@@ -41,7 +41,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfActorsGate do
41
41
 
42
42
  it 'redirects back to feature' do
43
43
  expect(last_response.status).to be(302)
44
- expect(last_response.headers['location']).to eq('/features/sp%20ace')
44
+ expect(last_response.headers['location']).to eq('/features/sp+ace')
45
45
  end
46
46
  end
47
47
 
@@ -58,7 +58,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfActorsGate do
58
58
 
59
59
  it 'redirects back to feature' do
60
60
  expect(last_response.status).to be(302)
61
- expect(last_response.headers['location']).to eq('/features/search?error=Invalid%20percentage%20of%20actors%20value:%20value%20must%20be%20a%20positive%20number%20less%20than%20or%20equal%20to%20100,%20but%20was%20555')
61
+ expect(last_response.headers['location']).to eq('/features/search?error=Invalid+percentage+of+actors+value%3A+value+must+be+a+positive+number+less+than+or+equal+to+100%2C+but+was+555')
62
62
  end
63
63
  end
64
64
  end
@@ -30,7 +30,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfTimeGate do
30
30
 
31
31
  context 'with space in feature name' do
32
32
  before do
33
- post 'features/sp%20ace/percentage_of_time',
33
+ post 'features/sp+ace/percentage_of_time',
34
34
  { 'value' => '24', 'authenticity_token' => token },
35
35
  'rack.session' => session
36
36
  end
@@ -41,7 +41,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfTimeGate do
41
41
 
42
42
  it 'redirects back to feature' do
43
43
  expect(last_response.status).to be(302)
44
- expect(last_response.headers['location']).to eq('/features/sp%20ace')
44
+ expect(last_response.headers['location']).to eq('/features/sp+ace')
45
45
  end
46
46
  end
47
47
 
@@ -58,7 +58,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfTimeGate do
58
58
 
59
59
  it 'redirects back to feature' do
60
60
  expect(last_response.status).to be(302)
61
- expect(last_response.headers['location']).to eq('/features/search?error=Invalid%20percentage%20of%20time%20value:%20value%20must%20be%20a%20positive%20number%20less%20than%20or%20equal%20to%20100,%20but%20was%20555')
61
+ expect(last_response.headers['location']).to eq('/features/search?error=Invalid+percentage+of+time+value%3A+value+must+be+a+positive+number+less+than+or+equal+to+100%2C+but+was+555')
62
62
  end
63
63
  end
64
64
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper-ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-11-19 00:00:00.000000000 Z
10
+ date: 2025-02-24 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rack
@@ -76,14 +75,14 @@ dependencies:
76
75
  requirements:
77
76
  - - "~>"
78
77
  - !ruby/object:Gem::Version
79
- version: 1.3.2
78
+ version: 1.3.3
80
79
  type: :runtime
81
80
  prerelease: false
82
81
  version_requirements: !ruby/object:Gem::Requirement
83
82
  requirements:
84
83
  - - "~>"
85
84
  - !ruby/object:Gem::Version
86
- version: 1.3.2
85
+ version: 1.3.3
87
86
  - !ruby/object:Gem::Dependency
88
87
  name: erubi
89
88
  requirement: !ruby/object:Gem::Requirement
@@ -110,15 +109,14 @@ dependencies:
110
109
  requirements:
111
110
  - - "<"
112
111
  - !ruby/object:Gem::Version
113
- version: '7'
112
+ version: '8'
114
113
  type: :runtime
115
114
  prerelease: false
116
115
  version_requirements: !ruby/object:Gem::Requirement
117
116
  requirements:
118
117
  - - "<"
119
118
  - !ruby/object:Gem::Version
120
- version: '7'
121
- description:
119
+ version: '8'
122
120
  email: support@flippercloud.io
123
121
  executables: []
124
122
  extensions: []
@@ -200,8 +198,8 @@ metadata:
200
198
  homepage_uri: https://www.flippercloud.io
201
199
  source_code_uri: https://github.com/flippercloud/flipper
202
200
  bug_tracker_uri: https://github.com/flippercloud/flipper/issues
203
- changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.3.2
204
- post_install_message:
201
+ changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.3.3
202
+ funding_uri: https://github.com/sponsors/flippercloud
205
203
  rdoc_options: []
206
204
  require_paths:
207
205
  - lib
@@ -216,8 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
214
  - !ruby/object:Gem::Version
217
215
  version: '0'
218
216
  requirements: []
219
- rubygems_version: 3.5.23
220
- signing_key:
217
+ rubygems_version: 3.6.5
221
218
  specification_version: 4
222
219
  summary: Feature flag UI for the Flipper gem
223
220
  test_files: