flipper-ui 1.1.1 → 1.2.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: ba4c25311e22e8d5664937df9eddd132c53d9e0edf38827deb5f729afea71cfe
4
- data.tar.gz: d9886bc3f1c888172ea496940f178ac7633464764cda2969c9dfd3bf789e1f62
3
+ metadata.gz: b33985781ada74b2666ef3b636288e1c5316b7f32f8178f3adafccf3f30e7c4f
4
+ data.tar.gz: 637de7cc0214932ea6fa47aa4d3a4d32e3b8e4dd9b4e97417a610a9405fc7898
5
5
  SHA512:
6
- metadata.gz: cc69bd99cb25c55c135230ca7648214b51b2f043631e9a8b46e387aea32f68d5c828d5da1464a3fba5d33293e907468c6761c8cab27a6e338eebd7548e2b719f
7
- data.tar.gz: a8087973bbec2641c3cdbeb99493be16fb1ea99da5fabf96a2b901de64cd2f8149e376c018fd13c0331e076864cf1d764ee757596554a8700caf1fabb1f1f707
6
+ metadata.gz: ebc76af3eda0bf9b60912dc58b99fcaf65677a485cfa9ed4ca7a52bcf12934a6870680eb702869faa47f930575cc4b1046b3ddc34c2958f5cf7b4a504dbd7f48
7
+ data.tar.gz: a94f123f0e800036d602df242825c0452e081ccb91010f7642ecb118888b85e35c8eba63377f1fa3e1b05037ced0d2e9938413d554d0b52683709dafad11e2f7
data/examples/ui/basic.ru CHANGED
@@ -42,8 +42,8 @@ Flipper::UI.configure do |config|
42
42
 
43
43
  config.actor_names_source = lambda do |_keys|
44
44
  {
45
- '1' => 'John',
46
- '6' => 'Brandon',
45
+ '1' => '<a href="https://johnnunemaker.com">John</a>',
46
+ '6' => '<a href="https://opensoul.org">Brandon</a>',
47
47
  }
48
48
  end
49
49
  end
data/flipper-ui.gemspec CHANGED
@@ -9,7 +9,7 @@ end
9
9
  Gem::Specification.new do |gem|
10
10
  gem.authors = ['John Nunemaker']
11
11
  gem.email = 'support@flippercloud.io'
12
- gem.summary = 'UI for the Flipper gem'
12
+ gem.summary = 'Feature flag UI for the Flipper gem'
13
13
  gem.license = 'MIT'
14
14
  gem.homepage = 'https://www.flippercloud.io/docs/ui'
15
15
 
@@ -53,6 +53,7 @@ module Flipper
53
53
  style-src 'self' 'unsafe-inline';
54
54
  style-src-attr 'unsafe-inline' ;
55
55
  style-src-elem 'self';
56
+ connect-src https://www.flippercloud.io;
56
57
  CSP
57
58
 
58
59
  # Public: Call this in subclasses so the action knows its route.
@@ -108,7 +109,7 @@ module Flipper
108
109
  @flipper = flipper
109
110
  @request = request
110
111
  @code = 200
111
- @headers = { 'content-type' => 'text/plain' }
112
+ @headers = {Rack::CONTENT_TYPE => 'text/plain'}
112
113
  @breadcrumbs =
113
114
  if Flipper::UI.configuration.application_breadcrumb_href
114
115
  [Breadcrumb.new('App', Flipper::UI.configuration.application_breadcrumb_href)]
@@ -158,7 +159,7 @@ module Flipper
158
159
  #
159
160
  # Returns a response.
160
161
  def view_response(name)
161
- header 'content-type', 'text/html'
162
+ header Rack::CONTENT_TYPE, 'text/html'
162
163
  header 'content-security-policy', CONTENT_SECURITY_POLICY
163
164
  body = view_with_layout { view_without_layout name }
164
165
  halt [@code, @headers, [body]]
@@ -171,7 +172,7 @@ module Flipper
171
172
  #
172
173
  # Returns a response.
173
174
  def json_response(object)
174
- header 'content-type', 'application/json'
175
+ header Rack::CONTENT_TYPE, 'application/json'
175
176
  body = case object
176
177
  when String
177
178
  object
@@ -63,6 +63,10 @@ module Flipper
63
63
  # Default is false.
64
64
  attr_accessor :confirm_fully_enable
65
65
 
66
+ # Public: if you want to get a confirm pop up box while disabling a feature
67
+ # Default is false.
68
+ attr_accessor :confirm_disable
69
+
66
70
  VALID_BANNER_CLASS_VALUES = %w(
67
71
  danger
68
72
  dark
@@ -91,6 +95,7 @@ module Flipper
91
95
  @show_feature_description_in_list = false
92
96
  @actors_separator = ','
93
97
  @confirm_fully_enable = false
98
+ @confirm_disable = true
94
99
  @read_only = false
95
100
  end
96
101
 
@@ -14,7 +14,18 @@ $(function () {
14
14
  e.preventDefault();
15
15
  }
16
16
  });
17
-
17
+
18
+ $("#disable_feature__button").on("click", function (e) {
19
+ const featureName = $(e.target).data("confirmation-text");
20
+ const promptMessage = prompt(
21
+ `Are you sure you want to disable this feature for everyone? Please enter the name of the feature to confirm it: ${featureName}`
22
+ );
23
+
24
+ if (promptMessage !== featureName) {
25
+ e.preventDefault();
26
+ }
27
+ });
28
+
18
29
  $("#delete_feature__button").on("click", function (e) {
19
30
  const featureName = $(e.target).data("confirmation-text");
20
31
  const promptMessage = prompt(
@@ -0,0 +1,33 @@
1
+ // Get the latest release from RubyGems.org and show a badge if it's not the current version
2
+ function checkLatestRelease() {
3
+ // Skip check if last check was less than 1 day ago
4
+ if(localStorage.getItem('flipper.releaseCheckedAt') > new Date().getTime() - 86400000) return
5
+
6
+ // store the last time we checked for a new version
7
+ localStorage.setItem('flipper.releaseCheckedAt', new Date().getTime())
8
+
9
+ fetch('https://www.flippercloud.io/release.json').then(response => {
10
+ // Something went wrong, so just give up
11
+ if(!response.ok) return
12
+
13
+ response.json().then(release => {
14
+ localStorage.setItem('flipper.release', JSON.stringify(release))
15
+ showReleaseBadge()
16
+ })
17
+ })
18
+ }
19
+
20
+ // Show a badge if a new release is available
21
+ function showReleaseBadge() {
22
+ const badge = document.querySelector('#new-version-badge')
23
+ const release = JSON.parse(localStorage.getItem('flipper.release') || false)
24
+
25
+ if(!badge || !release || badge.dataset.version === release.version) return
26
+
27
+ badge.innerText = `${release.version} available!`
28
+ badge.setAttribute('href', release.changelog_uri)
29
+ badge.classList.remove('d-none')
30
+ }
31
+
32
+ checkLatestRelease()
33
+ showReleaseBadge()
@@ -66,7 +66,7 @@
66
66
  <div class="col col-mr-auto pl-md-5">
67
67
  <h6 class="m-0">
68
68
  <% if Flipper::UI::Util.present?(@feature.actor_names[item]) %>
69
- <%= "#{@feature.actor_names[item]} (#{item})" %>
69
+ <%== Sanitize.fragment("#{@feature.actor_names[item]} (#{item})", Sanitize::Config::BASIC) %>
70
70
  <% else %>
71
71
  <%= item %>
72
72
  <% end %>
@@ -263,8 +263,13 @@
263
263
 
264
264
  <% unless @feature.off? %>
265
265
  <div class="col">
266
- <button type="submit" name="action" value="Disable" class="btn btn-outline-danger btn-block">
267
- <span class="d-block" data-toggle="tooltip" title="Disable for everyone by clearing all percentages, groups and actors.">
266
+ <button type="submit" name="action" value="Disable" <% if Flipper::UI.configuration.confirm_disable %>id="disable_feature__button"<% end %> class="btn btn-outline-danger btn-block">
267
+ <span class="d-block" data-toggle="tooltip"
268
+ <% if Flipper::UI.configuration.confirm_disable %>
269
+ data-confirmation-text="<%= feature_name %>"
270
+ <% end %>
271
+ title="Disable for everyone by clearing all percentages, groups and actors."
272
+ >
268
273
  Disable
269
274
  </span>
270
275
  </button>
@@ -21,6 +21,20 @@
21
21
  <a href="https://www.flippercloud.io/docs/ui?utm_source=oss&utm_medium=ui&utm_campaign=docs">Docs</a> &bull;
22
22
  <a href="<%= script_name %>/settings">Settings</a> &bull;
23
23
  Version: <%= Flipper::VERSION %>
24
+ <a href="#" class="badge badge-warning ml-2 d-none" style="font-size:100%" id="new-version-badge" data-version="<%= Flipper::VERSION %>">
25
+ </a>
26
+
27
+ <% if Flipper.deprecated_ruby_version? %>
28
+ <a href="https://github.com/flippercloud/flipper/pull/776" class="badge badge-danger ml-2" style="font-size:100%">
29
+ Ruby <%= RUBY_VERSION %> deprecated
30
+ </a>
31
+ <% end %>
32
+
33
+ <% if defined?(Rails) && Flipper::Engine.deprecated_rails_version? %>
34
+ <a href="https://github.com/flippercloud/flipper/pull/776" class="badge badge-danger ml-2" style="font-size:100%">
35
+ Rails <%= Rails.version %> deprecated
36
+ </a>
37
+ <% end %>
24
38
  </div>
25
39
 
26
40
  <nav aria-label="breadcrumb">
@@ -60,6 +74,7 @@
60
74
  <script src="<%= script_name + jquery_js[:src] %>" integrity="<%= jquery_js[:hash] %>" crossorigin="anonymous"></script>
61
75
  <script src="<%= script_name + popper_js[:src] %>" integrity="<%= popper_js[:hash] %>" crossorigin="anonymous"></script>
62
76
  <script src="<%= script_name + bootstrap_js[:src] %>" integrity="<%= bootstrap_js[:hash] %>" crossorigin="anonymous"></script>
63
- <script src="<%= script_name %>/js/application.js"></script>
77
+ <script src="<%= script_name %>/js/application.js?v=<%= Flipper::VERSION %>"></script>
78
+ <script src="<%= script_name %>/js/version.js?v=<%= Flipper::VERSION %>"></script>
64
79
  </body>
65
80
  </html>
data/lib/flipper/ui.rb CHANGED
@@ -22,7 +22,7 @@ module Flipper
22
22
  env_key = options.fetch(:env_key, 'flipper')
23
23
  rack_protection_options = options.fetch(:rack_protection, use: :authenticity_token)
24
24
 
25
- app = ->(_) { [200, { 'content-type' => 'text/html' }, ['']] }
25
+ app = ->(_) { [200, { Rack::CONTENT_TYPE => 'text/html' }, ['']] }
26
26
  builder = Rack::Builder.new
27
27
  yield builder if block_given?
28
28
  builder.use Rack::Protection, rack_protection_options
@@ -1,3 +1,13 @@
1
1
  module Flipper
2
- VERSION = '1.1.1'.freeze
2
+ VERSION = '1.2.0'.freeze
3
+
4
+ REQUIRED_RUBY_VERSION = '2.6'.freeze
5
+ NEXT_REQUIRED_RUBY_VERSION = '3.0'.freeze
6
+
7
+ REQUIRED_RAILS_VERSION = '5.2'.freeze
8
+ NEXT_REQUIRED_RAILS_VERSION = '6.1.0'.freeze
9
+
10
+ def self.deprecated_ruby_version?
11
+ Gem::Version.new(RUBY_VERSION) < Gem::Version.new(NEXT_REQUIRED_RUBY_VERSION)
12
+ end
3
13
  end
@@ -68,7 +68,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
68
68
 
69
69
  it 'redirects back to feature' do
70
70
  expect(last_response.status).to be(302)
71
- expect(last_response.headers['Location']).to eq('/features/search')
71
+ expect(last_response.headers['location']).to eq('/features/search')
72
72
  end
73
73
 
74
74
  context "when feature name contains space" do
@@ -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%20ace')
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%20is%20not%20a%20valid%20actor%20value.')
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%20is%20not%20a%20valid%20actor%20value.')
127
127
  end
128
128
  end
129
129
  end
@@ -175,7 +175,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
175
175
 
176
176
  it 'redirects back to feature' do
177
177
  expect(last_response.status).to be(302)
178
- expect(last_response.headers['Location']).to eq('/features/search')
178
+ expect(last_response.headers['location']).to eq('/features/search')
179
179
  end
180
180
 
181
181
  context 'value contains whitespace' do
@@ -25,7 +25,7 @@ RSpec.describe Flipper::UI::Actions::BooleanGate do
25
25
 
26
26
  it 'redirects back to feature' do
27
27
  expect(last_response.status).to be(302)
28
- expect(last_response.headers['Location']).to eq('/features/search')
28
+ expect(last_response.headers['location']).to eq('/features/search')
29
29
  end
30
30
  end
31
31
 
@@ -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%20ace')
47
47
  end
48
48
  end
49
49
 
@@ -61,7 +61,7 @@ RSpec.describe Flipper::UI::Actions::BooleanGate do
61
61
 
62
62
  it 'redirects back to feature' do
63
63
  expect(last_response.status).to be(302)
64
- expect(last_response.headers['Location']).to eq('/features/search')
64
+ expect(last_response.headers['location']).to eq('/features/search')
65
65
  end
66
66
  end
67
67
  end
@@ -33,12 +33,12 @@ RSpec.describe Flipper::UI::Actions::Features do
33
33
  end
34
34
 
35
35
  it 'sets content disposition' do
36
- expect(last_response.headers['Content-Disposition']).to match(/Attachment;filename=flipper_memory_[0-9]*\.json/)
36
+ expect(last_response.headers['content-disposition']).to match(/Attachment;filename=flipper_memory_[0-9]*\.json/)
37
37
  end
38
38
 
39
39
  it 'renders json' do
40
40
  data = JSON.parse(last_response.body)
41
- expect(last_response.headers['Content-Type']).to eq('application/json')
41
+ expect(last_response.headers['content-type']).to eq('application/json')
42
42
  expect(data['version']).to eq(1)
43
43
  expect(data['features']).to eq({
44
44
  "analytics" => {"boolean"=>nil, "expression"=>{"Equal"=>[{"Property"=>["plan"]}, "basic"]}, "groups"=>[], "actors"=>[], "percentage_of_actors"=>nil, "percentage_of_time"=>nil},
@@ -24,7 +24,7 @@ RSpec.describe Flipper::UI::Actions::Feature do
24
24
 
25
25
  it 'redirects to features' do
26
26
  expect(last_response.status).to be(302)
27
- expect(last_response.headers['Location']).to eq('/features')
27
+ expect(last_response.headers['location']).to eq('/features')
28
28
  end
29
29
 
30
30
  context "with space in feature name" do
@@ -41,7 +41,7 @@ RSpec.describe Flipper::UI::Actions::Feature do
41
41
 
42
42
  it 'redirects to features' do
43
43
  expect(last_response.status).to be(302)
44
- expect(last_response.headers['Location']).to eq('/features')
44
+ expect(last_response.headers['location']).to eq('/features')
45
45
  end
46
46
  end
47
47
 
@@ -80,7 +80,7 @@ RSpec.describe Flipper::UI::Actions::Feature do
80
80
 
81
81
  it 'redirects to features' do
82
82
  expect(last_response.status).to be(302)
83
- expect(last_response.headers['Location']).to eq('/features')
83
+ expect(last_response.headers['location']).to eq('/features')
84
84
  end
85
85
  end
86
86
 
@@ -138,14 +138,35 @@ RSpec.describe Flipper::UI::Actions::Feature do
138
138
  }
139
139
  }
140
140
  end
141
-
142
- get '/features/search'
143
141
  end
144
142
 
145
143
  it 'renders template with custom actor names' do
144
+ get '/features/search'
146
145
  expect(last_response.body).to include('Some Actor Name (some_actor_name)')
147
146
  expect(last_response.body).not_to include('Some Other Actor Name')
148
147
  end
148
+
149
+ it 'allows basic html' do
150
+ Flipper::UI.configure do |config|
151
+ config.actor_names_source = lambda { |_keys|
152
+ { "some_actor_name" => '<a href="/users/some_actor_name">Some Actor Name</a>', }
153
+ }
154
+ end
155
+
156
+ get '/features/search'
157
+ expect(last_response.body).to include('<a href="/users/some_actor_name" rel="nofollow">Some Actor Name</a>')
158
+ end
159
+
160
+ it 'sanitizes dangerous markup' do
161
+ Flipper::UI.configure do |config|
162
+ config.actor_names_source = lambda { |_keys|
163
+ { "some_actor_name" => '<a href="javascript:alert(\'hello\')">Some Actor Name</a>', }
164
+ }
165
+ end
166
+
167
+ get '/features/search'
168
+ expect(last_response.body).not_to include('javascript:alert')
169
+ end
149
170
  end
150
171
  end
151
172
 
@@ -104,7 +104,7 @@ RSpec.describe Flipper::UI::Actions::Features do
104
104
 
105
105
  it 'redirects to feature' do
106
106
  expect(last_response.status).to be(302)
107
- expect(last_response.headers['Location']).to eq('/features/notifications_next')
107
+ expect(last_response.headers['location']).to eq('/features/notifications_next')
108
108
  end
109
109
 
110
110
  context 'feature name has whitespace at beginning and end' do
@@ -124,7 +124,7 @@ RSpec.describe Flipper::UI::Actions::Features do
124
124
 
125
125
  it 'redirects to feature' do
126
126
  expect(last_response.status).to be(302)
127
- expect(last_response.headers['Location']).to eq('/features/notifications%20next')
127
+ expect(last_response.headers['location']).to eq('/features/notifications%20next')
128
128
  end
129
129
  end
130
130
 
@@ -138,7 +138,7 @@ RSpec.describe Flipper::UI::Actions::Features do
138
138
 
139
139
  it 'redirects back to feature' do
140
140
  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.')
141
+ expect(last_response.headers['location']).to eq('/features/new?error=%22%22%20is%20not%20a%20valid%20feature%20name.')
142
142
  end
143
143
  end
144
144
 
@@ -151,7 +151,7 @@ RSpec.describe Flipper::UI::Actions::Features do
151
151
 
152
152
  it 'redirects back to feature' do
153
153
  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.')
154
+ expect(last_response.headers['location']).to eq('/features/new?error=%22%22%20is%20not%20a%20valid%20feature%20name.')
155
155
  end
156
156
  end
157
157
  end
@@ -55,7 +55,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do
55
55
 
56
56
  it 'redirects back to feature' do
57
57
  expect(last_response.status).to be(302)
58
- expect(last_response.headers['Location']).to eq('/features/search')
58
+ expect(last_response.headers['location']).to eq('/features/search')
59
59
  end
60
60
 
61
61
  context 'feature name contains space' do
@@ -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%20ace')
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%20group%20named%20%22not_here%22%20has%20not%20been%20registered.')
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%20group%20named%20%22%22%20has%20not%20been%20registered.')
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%20group%20named%20%22%22%20has%20not%20been%20registered.')
111
111
  end
112
112
  end
113
113
  end
@@ -129,7 +129,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do
129
129
 
130
130
  it 'redirects back to feature' do
131
131
  expect(last_response.status).to be(302)
132
- expect(last_response.headers['Location']).to eq('/features/search')
132
+ expect(last_response.headers['location']).to eq('/features/search')
133
133
  end
134
134
 
135
135
  context 'group name contains whitespace' do
@@ -8,7 +8,7 @@ RSpec.describe Flipper::UI::Actions::Home do
8
8
 
9
9
  it 'responds with redirect' do
10
10
  expect(last_response.status).to be(302)
11
- expect(last_response.headers['Location']).to eq('/features')
11
+ expect(last_response.headers['location']).to eq('/features')
12
12
  end
13
13
  end
14
14
  end
@@ -35,7 +35,7 @@ RSpec.describe Flipper::UI::Actions::Import do
35
35
 
36
36
  it 'responds with redirect to settings' do
37
37
  expect(last_response.status).to be(302)
38
- expect(last_response.headers['Location']).to eq('/features')
38
+ expect(last_response.headers['location']).to eq('/features')
39
39
  end
40
40
  end
41
41
  end
@@ -24,7 +24,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfActorsGate do
24
24
 
25
25
  it 'redirects back to feature' do
26
26
  expect(last_response.status).to be(302)
27
- expect(last_response.headers['Location']).to eq('/features/search')
27
+ expect(last_response.headers['location']).to eq('/features/search')
28
28
  end
29
29
  end
30
30
 
@@ -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%20ace')
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%20percentage%20of%20actors%20value:%20value%20must%20be%20a%20positive%20number%20less%20than%20or%20equal%20to%20100,%20but%20was%20555')
62
62
  end
63
63
  end
64
64
  end
@@ -24,7 +24,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfTimeGate do
24
24
 
25
25
  it 'redirects back to feature' do
26
26
  expect(last_response.status).to be(302)
27
- expect(last_response.headers['Location']).to eq('/features/search')
27
+ expect(last_response.headers['location']).to eq('/features/search')
28
28
  end
29
29
  end
30
30
 
@@ -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%20ace')
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%20percentage%20of%20time%20value:%20value%20must%20be%20a%20positive%20number%20less%20than%20or%20equal%20to%20100,%20but%20was%20555')
62
62
  end
63
63
  end
64
64
  end
@@ -42,7 +42,7 @@ RSpec.describe Flipper::UI do
42
42
  { 'value' => 'User;6', 'operation' => 'enable', 'authenticity_token' => token },
43
43
  'rack.session' => session
44
44
  expect(last_response.status).to be(302)
45
- expect(last_response.headers['Location']).to eq('/features/refactor-images')
45
+ expect(last_response.headers['location']).to eq('/features/refactor-images')
46
46
  end
47
47
 
48
48
  describe 'configure' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper-ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-09 00:00:00.000000000 Z
11
+ date: 2024-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -56,14 +56,14 @@ dependencies:
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: 1.1.1
59
+ version: 1.2.0
60
60
  type: :runtime
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: 1.1.1
66
+ version: 1.2.0
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: erubi
69
69
  requirement: !ruby/object:Gem::Requirement
@@ -139,6 +139,7 @@ files:
139
139
  - lib/flipper/ui/public/js/bootstrap-4.6.0.min.js
140
140
  - lib/flipper/ui/public/js/jquery-3.6.0.slim.js
141
141
  - lib/flipper/ui/public/js/popper-1.12.9.min.js
142
+ - lib/flipper/ui/public/js/version.js
142
143
  - lib/flipper/ui/util.rb
143
144
  - lib/flipper/ui/views/add_actor.erb
144
145
  - lib/flipper/ui/views/add_feature.erb
@@ -178,7 +179,7 @@ metadata:
178
179
  homepage_uri: https://www.flippercloud.io
179
180
  source_code_uri: https://github.com/flippercloud/flipper
180
181
  bug_tracker_uri: https://github.com/flippercloud/flipper/issues
181
- changelog_uri: https://github.com/flippercloud/flipper/blob/main/Changelog.md
182
+ changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.2.0
182
183
  post_install_message:
183
184
  rdoc_options: []
184
185
  require_paths:
@@ -194,10 +195,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
195
  - !ruby/object:Gem::Version
195
196
  version: '0'
196
197
  requirements: []
197
- rubygems_version: 3.4.10
198
+ rubygems_version: 3.5.3
198
199
  signing_key:
199
200
  specification_version: 4
200
- summary: UI for the Flipper gem
201
+ summary: Feature flag UI for the Flipper gem
201
202
  test_files:
202
203
  - spec/flipper/ui/action_spec.rb
203
204
  - spec/flipper/ui/actions/actors_gate_spec.rb