flipper-ui 0.16.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +5 -5
  2. data/docs/ui/README.md +29 -8
  3. data/examples/ui/basic.ru +19 -0
  4. data/flipper-ui.gemspec +1 -2
  5. data/lib/flipper/ui.rb +4 -7
  6. data/lib/flipper/ui/action.rb +4 -7
  7. data/lib/flipper/ui/actions/feature.rb +5 -2
  8. data/lib/flipper/ui/actions/features.rb +1 -0
  9. data/lib/flipper/ui/actions/file.rb +1 -1
  10. data/lib/flipper/ui/assets/javascripts/application.coffee +5 -3
  11. data/lib/flipper/ui/configuration.rb +25 -10
  12. data/lib/flipper/ui/decorators/feature.rb +39 -13
  13. data/lib/flipper/ui/public/css/application.css +20 -6493
  14. data/lib/flipper/ui/public/js/application.js +5 -5
  15. data/lib/flipper/ui/util.rb +40 -0
  16. data/lib/flipper/ui/views/add_actor.erb +2 -2
  17. data/lib/flipper/ui/views/add_feature.erb +2 -2
  18. data/lib/flipper/ui/views/add_group.erb +1 -1
  19. data/lib/flipper/ui/views/feature.erb +200 -181
  20. data/lib/flipper/ui/views/features.erb +50 -36
  21. data/lib/flipper/ui/views/layout.erb +4 -14
  22. data/lib/flipper/version.rb +1 -1
  23. data/spec/flipper/ui/action_spec.rb +61 -42
  24. data/spec/flipper/ui/actions/actors_gate_spec.rb +9 -13
  25. data/spec/flipper/ui/actions/feature_spec.rb +14 -16
  26. data/spec/flipper/ui/actions/features_spec.rb +49 -14
  27. data/spec/flipper/ui/actions/file_spec.rb +0 -10
  28. data/spec/flipper/ui/actions/groups_gate_spec.rb +0 -6
  29. data/spec/flipper/ui/actions/percentage_of_actors_gate_spec.rb +0 -2
  30. data/spec/flipper/ui/actions/percentage_of_time_gate_spec.rb +0 -2
  31. data/spec/flipper/ui/configuration_spec.rb +32 -34
  32. data/spec/flipper/ui/decorators/feature_spec.rb +2 -32
  33. data/spec/flipper/ui_spec.rb +1 -1
  34. metadata +17 -129
  35. data/lib/flipper/ui/assets/stylesheets/.DS_Store +0 -0
  36. data/lib/flipper/ui/assets/stylesheets/application.scss +0 -19
  37. data/lib/flipper/ui/assets/stylesheets/bootstrap/_alert.scss +0 -51
  38. data/lib/flipper/ui/assets/stylesheets/bootstrap/_badge.scss +0 -47
  39. data/lib/flipper/ui/assets/stylesheets/bootstrap/_breadcrumb.scss +0 -38
  40. data/lib/flipper/ui/assets/stylesheets/bootstrap/_button-group.scss +0 -166
  41. data/lib/flipper/ui/assets/stylesheets/bootstrap/_buttons.scss +0 -143
  42. data/lib/flipper/ui/assets/stylesheets/bootstrap/_card.scss +0 -270
  43. data/lib/flipper/ui/assets/stylesheets/bootstrap/_carousel.scss +0 -191
  44. data/lib/flipper/ui/assets/stylesheets/bootstrap/_close.scss +0 -34
  45. data/lib/flipper/ui/assets/stylesheets/bootstrap/_code.scss +0 -56
  46. data/lib/flipper/ui/assets/stylesheets/bootstrap/_custom-forms.scss +0 -297
  47. data/lib/flipper/ui/assets/stylesheets/bootstrap/_dropdown.scss +0 -131
  48. data/lib/flipper/ui/assets/stylesheets/bootstrap/_forms.scss +0 -333
  49. data/lib/flipper/ui/assets/stylesheets/bootstrap/_functions.scss +0 -86
  50. data/lib/flipper/ui/assets/stylesheets/bootstrap/_grid.scss +0 -52
  51. data/lib/flipper/ui/assets/stylesheets/bootstrap/_images.scss +0 -42
  52. data/lib/flipper/ui/assets/stylesheets/bootstrap/_input-group.scss +0 -159
  53. data/lib/flipper/ui/assets/stylesheets/bootstrap/_jumbotron.scss +0 -16
  54. data/lib/flipper/ui/assets/stylesheets/bootstrap/_list-group.scss +0 -115
  55. data/lib/flipper/ui/assets/stylesheets/bootstrap/_media.scss +0 -8
  56. data/lib/flipper/ui/assets/stylesheets/bootstrap/_mixins.scss +0 -42
  57. data/lib/flipper/ui/assets/stylesheets/bootstrap/_modal.scss +0 -168
  58. data/lib/flipper/ui/assets/stylesheets/bootstrap/_nav.scss +0 -118
  59. data/lib/flipper/ui/assets/stylesheets/bootstrap/_navbar.scss +0 -311
  60. data/lib/flipper/ui/assets/stylesheets/bootstrap/_pagination.scss +0 -77
  61. data/lib/flipper/ui/assets/stylesheets/bootstrap/_popover.scss +0 -183
  62. data/lib/flipper/ui/assets/stylesheets/bootstrap/_print.scss +0 -124
  63. data/lib/flipper/ui/assets/stylesheets/bootstrap/_progress.scss +0 -33
  64. data/lib/flipper/ui/assets/stylesheets/bootstrap/_reboot.scss +0 -482
  65. data/lib/flipper/ui/assets/stylesheets/bootstrap/_root.scss +0 -19
  66. data/lib/flipper/ui/assets/stylesheets/bootstrap/_tables.scss +0 -180
  67. data/lib/flipper/ui/assets/stylesheets/bootstrap/_tooltip.scss +0 -115
  68. data/lib/flipper/ui/assets/stylesheets/bootstrap/_transitions.scss +0 -36
  69. data/lib/flipper/ui/assets/stylesheets/bootstrap/_type.scss +0 -125
  70. data/lib/flipper/ui/assets/stylesheets/bootstrap/_utilities.scss +0 -14
  71. data/lib/flipper/ui/assets/stylesheets/bootstrap/_variables.scss +0 -894
  72. data/lib/flipper/ui/assets/stylesheets/bootstrap/bootstrap-grid.scss +0 -32
  73. data/lib/flipper/ui/assets/stylesheets/bootstrap/bootstrap-reboot.scss +0 -12
  74. data/lib/flipper/ui/assets/stylesheets/bootstrap/bootstrap.scss +0 -42
  75. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_alert.scss +0 -13
  76. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_background-variant.scss +0 -21
  77. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_badge.scss +0 -12
  78. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_border-radius.scss +0 -35
  79. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_box-shadow.scss +0 -5
  80. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_breakpoints.scss +0 -123
  81. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_buttons.scss +0 -109
  82. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_caret.scss +0 -65
  83. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_clearfix.scss +0 -7
  84. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_float.scss +0 -11
  85. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_forms.scss +0 -137
  86. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_gradients.scss +0 -45
  87. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_grid-framework.scss +0 -67
  88. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_grid.scss +0 -52
  89. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_hover.scss +0 -39
  90. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_image.scss +0 -36
  91. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_list-group.scss +0 -21
  92. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_lists.scss +0 -7
  93. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_nav-divider.scss +0 -10
  94. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_navbar-align.scss +0 -10
  95. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_pagination.scss +0 -22
  96. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_reset-text.scss +0 -17
  97. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_resize.scss +0 -6
  98. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_screen-reader.scss +0 -35
  99. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_size.scss +0 -6
  100. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_table-row.scss +0 -30
  101. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_text-emphasis.scss +0 -14
  102. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_text-hide.scss +0 -9
  103. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_text-truncate.scss +0 -8
  104. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_transition.scss +0 -9
  105. data/lib/flipper/ui/assets/stylesheets/bootstrap/mixins/_visibility.scss +0 -7
  106. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_align.scss +0 -8
  107. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_background.scss +0 -19
  108. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_borders.scss +0 -59
  109. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_clearfix.scss +0 -3
  110. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_display.scss +0 -38
  111. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_embed.scss +0 -52
  112. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_flex.scss +0 -46
  113. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_float.scss +0 -9
  114. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_position.scss +0 -36
  115. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_screenreaders.scss +0 -11
  116. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_sizing.scss +0 -12
  117. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_spacing.scss +0 -51
  118. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_text.scss +0 -52
  119. data/lib/flipper/ui/assets/stylesheets/bootstrap/utilities/_visibility.scss +0 -11
  120. data/lib/flipper/ui/assets/stylesheets/primer/.scss-lint.yml +0 -446
  121. data/lib/flipper/ui/assets/stylesheets/primer/_alerts.scss +0 -106
  122. data/lib/flipper/ui/assets/stylesheets/primer/_avatars.scss +0 -36
  123. data/lib/flipper/ui/assets/stylesheets/primer/_base.scss +0 -40
  124. data/lib/flipper/ui/assets/stylesheets/primer/_blankslate.scss +0 -96
  125. data/lib/flipper/ui/assets/stylesheets/primer/_buttons.scss +0 -404
  126. data/lib/flipper/ui/assets/stylesheets/primer/_counter.scss +0 -10
  127. data/lib/flipper/ui/assets/stylesheets/primer/_filter-list.scss +0 -68
  128. data/lib/flipper/ui/assets/stylesheets/primer/_flex-table.scss +0 -20
  129. data/lib/flipper/ui/assets/stylesheets/primer/_forms.scss +0 -756
  130. data/lib/flipper/ui/assets/stylesheets/primer/_layout.scss +0 -69
  131. data/lib/flipper/ui/assets/stylesheets/primer/_menu.scss +0 -113
  132. data/lib/flipper/ui/assets/stylesheets/primer/_mixins.scss +0 -53
  133. data/lib/flipper/ui/assets/stylesheets/primer/_normalize.scss +0 -425
  134. data/lib/flipper/ui/assets/stylesheets/primer/_states.scss +0 -32
  135. data/lib/flipper/ui/assets/stylesheets/primer/_tabnav.scss +0 -65
  136. data/lib/flipper/ui/assets/stylesheets/primer/_tooltips.scss +0 -255
  137. data/lib/flipper/ui/assets/stylesheets/primer/_truncate.scss +0 -27
  138. data/lib/flipper/ui/assets/stylesheets/primer/_type.scss +0 -92
  139. data/lib/flipper/ui/assets/stylesheets/primer/_utility.scss +0 -73
  140. data/lib/flipper/ui/assets/stylesheets/primer/_variables.scss +0 -34
  141. data/lib/flipper/ui/assets/stylesheets/primer/primer.scss +0 -39
  142. data/lib/flipper/ui/eruby.rb +0 -11
  143. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
  144. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.svg +0 -288
  145. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
  146. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
  147. data/lib/flipper/ui/public/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
  148. data/lib/flipper/ui/public/images/remove.png +0 -0
  149. data/lib/flipper/ui/public/octicons/octicons.less +0 -235
  150. data/lib/flipper/ui/public/octicons/sprockets-octicons.scss +0 -232
@@ -1,43 +1,57 @@
1
1
  <% if @show_blank_slate %>
2
2
  <div class="jumbotron text-center">
3
- <span class="mega-octicon octicon-plus"></span>
4
- <span class="mega-octicon octicon-list-unordered"></span>
5
- <span class="mega-octicon octicon-zap"></span>
6
- <h4>But I've got a blank space baby...</h4>
7
- <p>And I'll flip your features.</p>
8
- <div class="embed-responsive embed-responsive-16by9">
9
- <iframe class="embed-responsive-item" width="560" height="315" src="https://www.youtube.com/embed/e-ORhEE9VVg" frameborder="0" allowfullscreen></iframe>
10
- </div>
3
+ <% if Flipper::UI.configuration.fun %>
4
+ <h4>But I've got a blank space baby...</h4>
5
+ <p>And I'll flip your features.</p>
6
+ <%- if Flipper::UI.configuration.feature_creation_enabled -%>
7
+ <p>
8
+ <a class="btn btn-primary btn-sm" href="<%= script_name %>/features/new">Add Feature</a>
9
+ </p>
10
+ <%- end -%>
11
+ <div class="embed-responsive embed-responsive-16by9">
12
+ <iframe class="embed-responsive-item" width="560" height="315" src="https://www.youtube.com/embed/e-ORhEE9VVg" frameborder="0" allowfullscreen></iframe>
13
+ </div>
14
+ <% else %>
15
+ <h4>Getting Started</h4>
16
+ <p class="mb-1">You have not added any features to configure yet.</p>
17
+ <%- if Flipper::UI.configuration.feature_creation_enabled -%>
18
+ <p class="mt-2">
19
+ <a class="btn btn-primary btn-sm" href="<%= script_name %>/features/new">Add Feature</a>
20
+ </p>
21
+ <% else %>
22
+ <p>
23
+ Check the <a href="https://github.com/jnunemaker/flipper#examples">examples</a> to
24
+ learn how to add one.
25
+ </p>
26
+ <%- end -%>
27
+ <% end %>
11
28
  </div>
12
29
  <% else %>
13
30
  <div class="card">
14
- <h4 class="card-header">Features</h4>
15
- <table class="table">
16
- <thead>
17
- <tr class="d-flex">
18
- <th class="col-1">
19
- <span class="octicon octicon-squirrel"></span>
20
- </th>
21
- <th class="col">Feature</th>
22
- <th class="col">Enabled Gates</th>
23
- </tr>
24
- </thead>
25
- <tbody>
26
- <% @features.each do |feature| %>
27
- <tr class="d-flex">
28
- <td class="col-1">
29
- <span class="octicon octicon-squirrel <%= feature.color_class %>"></span>
30
- </td>
31
- <td class="col">
32
- <a href="<%= "#{script_name}/features/#{feature.key}" %>">
33
- <%= feature.key %></a>
34
- </td>
35
- <td class="col">
36
- <%= feature.pretty_enabled_gate_names %>
37
- </td>
38
- </tr>
39
- <% end %>
40
- </tbody>
41
- </table>
31
+ <div class="card-header">
32
+ <%- if Flipper::UI.configuration.feature_creation_enabled -%>
33
+ <div class="float-right">
34
+ <a class="btn btn-primary btn-sm" href="<%= script_name %>/features/new">Add Feature</a>
35
+ </div>
36
+ <%- end -%>
37
+ <h4 class="m-0">Features</h4>
38
+ </div>
39
+ <div class="card-body py-0">
40
+ <% @features.each do |feature| %>
41
+ <div class="feature row align-items-center mt-0 px-3 border-bottom">
42
+ <div class="col-1 col-md-auto">
43
+ <span class="octicon octicon-squirrel <%= feature.color_class %>" data-toggle="tooltip" title=<%= feature.state.to_s.capitalize %>></span>
44
+ </div>
45
+ <div class="col-10">
46
+ <a href="<%= "#{script_name}/features/#{feature.key}" %>" class="d-block px-0 py-3 btn text-left text-dark">
47
+ <div class="text-truncate"><%= feature.key %></div>
48
+ <div class="text-muted text-truncate">
49
+ <%== feature.gates_in_words %>
50
+ </div>
51
+ </a>
52
+ </div>
53
+ </div>
54
+ <% end %>
55
+ </div>
42
56
  </div>
43
57
  <% end %>
@@ -6,17 +6,12 @@
6
6
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1">
8
8
 
9
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
9
10
  <link rel="stylesheet" href="<%= script_name %>/octicons/octicons.css">
10
11
  <link rel="stylesheet" href="<%= script_name %>/css/application.css">
11
-
12
- <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
13
- <!--[if lt IE 9]>
14
- <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
15
- <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
16
- <![endif]-->
17
12
  </head>
18
- <body>
19
- <div class="container">
13
+ <body class="py-4">
14
+ <div class="container mw-600">
20
15
  <%- unless Flipper::UI.configuration.banner_text.nil? -%>
21
16
  <div class="alert alert-<%= Flipper::UI.configuration.banner_class %> text-center font-weight-bold">
22
17
  <%= Flipper::UI.configuration.banner_text %>
@@ -24,7 +19,7 @@
24
19
  <%- end -%>
25
20
 
26
21
  <nav aria-label="breadcrumb">
27
- <ol class="breadcrumb bg-white border border-light align-items-center">
22
+ <ol class="breadcrumb bg-white border align-items-center mb-4">
28
23
  <% @breadcrumbs.each do |breadcrumb| %>
29
24
  <li class="breadcrumb-item <% if breadcrumb.active? %>active<% end %>">
30
25
  <% if breadcrumb.active? %>
@@ -34,11 +29,6 @@
34
29
  <% end %>
35
30
  </li>
36
31
  <% end %>
37
- <li class="ml-auto">
38
- <%- if Flipper::UI.configuration.feature_creation_enabled -%>
39
- <a class="btn btn-sm btn-light" href="<%= script_name %>/features/new">Add Feature</a>
40
- <%- end -%>
41
- </li>
42
32
  </ol>
43
33
  </nav>
44
34
 
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.16.0'.freeze
2
+ VERSION = '0.18.0'.freeze
3
3
  end
@@ -1,59 +1,78 @@
1
1
  require 'helper'
2
2
 
3
3
  RSpec.describe Flipper::UI::Action do
4
- let(:action_subclass) do
5
- Class.new(described_class) do
6
- def noooope
7
- raise 'should never run this'
8
- end
4
+ describe 'request methods' do
5
+ let(:action_subclass) do
6
+ Class.new(described_class) do
7
+ def noooope
8
+ raise 'should never run this'
9
+ end
9
10
 
10
- def get
11
- [200, {}, 'get']
12
- end
11
+ def get
12
+ [200, {}, 'get']
13
+ end
13
14
 
14
- def post
15
- [200, {}, 'post']
16
- end
15
+ def post
16
+ [200, {}, 'post']
17
+ end
17
18
 
18
- def put
19
- [200, {}, 'put']
20
- end
19
+ def put
20
+ [200, {}, 'put']
21
+ end
21
22
 
22
- def delete
23
- [200, {}, 'delete']
23
+ def delete
24
+ [200, {}, 'delete']
25
+ end
24
26
  end
25
27
  end
26
- end
27
28
 
28
- it "won't run method that isn't whitelisted" do
29
- fake_request = Struct.new(:request_method, :env, :session).new('NOOOOPE', {}, {})
30
- action = action_subclass.new(flipper, fake_request)
31
- expect do
32
- action.run
33
- end.to raise_error(Flipper::UI::RequestMethodNotSupported)
34
- end
29
+ it "won't run method that isn't whitelisted" do
30
+ fake_request = Struct.new(:request_method, :env, :session).new('NOOOOPE', {}, {})
31
+ action = action_subclass.new(flipper, fake_request)
32
+ expect do
33
+ action.run
34
+ end.to raise_error(Flipper::UI::RequestMethodNotSupported)
35
+ end
35
36
 
36
- it 'will run get' do
37
- fake_request = Struct.new(:request_method, :env, :session).new('GET', {}, {})
38
- action = action_subclass.new(flipper, fake_request)
39
- expect(action.run).to eq([200, {}, 'get'])
40
- end
37
+ it 'will run get' do
38
+ fake_request = Struct.new(:request_method, :env, :session).new('GET', {}, {})
39
+ action = action_subclass.new(flipper, fake_request)
40
+ expect(action.run).to eq([200, {}, 'get'])
41
+ end
41
42
 
42
- it 'will run post' do
43
- fake_request = Struct.new(:request_method, :env, :session).new('POST', {}, {})
44
- action = action_subclass.new(flipper, fake_request)
45
- expect(action.run).to eq([200, {}, 'post'])
46
- end
43
+ it 'will run post' do
44
+ fake_request = Struct.new(:request_method, :env, :session).new('POST', {}, {})
45
+ action = action_subclass.new(flipper, fake_request)
46
+ expect(action.run).to eq([200, {}, 'post'])
47
+ end
47
48
 
48
- it 'will run put' do
49
- fake_request = Struct.new(:request_method, :env, :session).new('PUT', {}, {})
50
- action = action_subclass.new(flipper, fake_request)
51
- expect(action.run).to eq([200, {}, 'put'])
49
+ it 'will run put' do
50
+ fake_request = Struct.new(:request_method, :env, :session).new('PUT', {}, {})
51
+ action = action_subclass.new(flipper, fake_request)
52
+ expect(action.run).to eq([200, {}, 'put'])
53
+ end
52
54
  end
53
55
 
54
- it 'will run delete' do
55
- fake_request = Struct.new(:request_method, :env, :session).new('DELETE', {}, {})
56
- action = action_subclass.new(flipper, fake_request)
57
- expect(action.run).to eq([200, {}, 'delete'])
56
+ describe 'FeatureNameFromRoute' do
57
+ let(:action_subclass) do
58
+ Class.new(described_class) do |parent|
59
+ include parent::FeatureNameFromRoute
60
+
61
+ route %r{\A/features/(?<feature_name>.*)\Z}
62
+
63
+ def get
64
+ [200, { feature_name: feature_name }, 'get']
65
+ end
66
+ end
67
+ end
68
+
69
+ it 'decodes feature_name' do
70
+ requested_feature_name = Rack::Utils.escape("team:side_pane")
71
+ fake_request = Struct
72
+ .new(:request_method, :env, :session, :path_info)
73
+ .new('GET', {}, {}, "/features/#{requested_feature_name}")
74
+ action = action_subclass.new(flipper, fake_request)
75
+ expect(action.run).to eq([200, { feature_name: "team:side_pane" }, 'get'])
76
+ end
58
77
  end
59
78
  end
@@ -44,7 +44,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
44
44
 
45
45
  describe 'POST /features/:feature/actors' do
46
46
  context 'enabling an actor' do
47
- let(:value) { 'User:6' }
47
+ let(:value) { 'User;6' }
48
48
 
49
49
  before do
50
50
  post 'features/search/actors',
@@ -53,7 +53,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
53
53
  end
54
54
 
55
55
  it 'adds item to members' do
56
- expect(flipper[:search].actors_value).to include('User:6')
56
+ expect(flipper[:search].actors_value).to include('User;6')
57
57
  end
58
58
 
59
59
  it 'redirects back to feature' do
@@ -62,10 +62,10 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
62
62
  end
63
63
 
64
64
  context 'value contains whitespace' do
65
- let(:value) { ' User:6 ' }
65
+ let(:value) { ' User;6 ' }
66
66
 
67
67
  it 'adds item without whitespace' do
68
- expect(flipper[:search].actors_value).to include('User:6')
68
+ expect(flipper[:search].actors_value).to include('User;6')
69
69
  end
70
70
  end
71
71
 
@@ -73,39 +73,35 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
73
73
  context 'empty value' do
74
74
  let(:value) { '' }
75
75
 
76
- # rubocop:disable Metrics/LineLength
77
76
  it 'redirects back to feature' do
78
77
  expect(last_response.status).to be(302)
79
78
  expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22+is+not+a+valid+actor+value.')
80
79
  end
81
- # rubocop:enable Metrics/LineLength
82
80
  end
83
81
 
84
82
  context 'nil value' do
85
83
  let(:value) { nil }
86
84
 
87
- # rubocop:disable Metrics/LineLength
88
85
  it 'redirects back to feature' do
89
86
  expect(last_response.status).to be(302)
90
87
  expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22+is+not+a+valid+actor+value.')
91
88
  end
92
- # rubocop:enable Metrics/LineLength
93
89
  end
94
90
  end
95
91
  end
96
92
 
97
93
  context 'disabling an actor' do
98
- let(:value) { 'User:6' }
94
+ let(:value) { 'User;6' }
99
95
 
100
96
  before do
101
- flipper[:search].enable_actor Flipper::Actor.new('User:6')
97
+ flipper[:search].enable_actor Flipper::Actor.new('User;6')
102
98
  post 'features/search/actors',
103
99
  { 'value' => value, 'operation' => 'disable', 'authenticity_token' => token },
104
100
  'rack.session' => session
105
101
  end
106
102
 
107
103
  it 'removes item from members' do
108
- expect(flipper[:search].actors_value).not_to include('User:6')
104
+ expect(flipper[:search].actors_value).not_to include('User;6')
109
105
  end
110
106
 
111
107
  it 'redirects back to feature' do
@@ -114,10 +110,10 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
114
110
  end
115
111
 
116
112
  context 'value contains whitespace' do
117
- let(:value) { ' User:6 ' }
113
+ let(:value) { ' User;6 ' }
118
114
 
119
115
  it 'removes item without whitespace' do
120
- expect(flipper[:search].actors_value).not_to include('User:6')
116
+ expect(flipper[:search].actors_value).not_to include('User;6')
121
117
  end
122
118
  end
123
119
  end
@@ -70,6 +70,15 @@ RSpec.describe Flipper::UI::Actions::Feature do
70
70
 
71
71
  describe 'GET /features/:feature' do
72
72
  before do
73
+ Flipper::UI.configure do |config|
74
+ config.descriptions_source = lambda { |_keys|
75
+ {
76
+ "stats" => "Most awesome stats",
77
+ "search" => "Most in-depth search",
78
+ }
79
+ }
80
+ end
81
+
73
82
  get '/features/search'
74
83
  end
75
84
 
@@ -81,10 +90,11 @@ RSpec.describe Flipper::UI::Actions::Feature do
81
90
  expect(last_response.body).to include('search')
82
91
  expect(last_response.body).to include('Enable')
83
92
  expect(last_response.body).to include('Disable')
84
- expect(last_response.body).to include('Actors')
85
- expect(last_response.body).to include('Groups')
86
- expect(last_response.body).to include('Percentage of Time')
87
- expect(last_response.body).to include('Percentage of Actors')
93
+ expect(last_response.body).to include('No actors enabled')
94
+ expect(last_response.body).to include('No groups enabled')
95
+ expect(last_response.body).to include('Enabled for 0% of time')
96
+ expect(last_response.body).to include('Enabled for 0% of actors')
97
+ expect(last_response.body).to include('Most in-depth search')
88
98
  end
89
99
  end
90
100
 
@@ -99,12 +109,6 @@ RSpec.describe Flipper::UI::Actions::Feature do
99
109
 
100
110
  it 'renders template' do
101
111
  expect(last_response.body).to include('search_features')
102
- expect(last_response.body).to include('Enable')
103
- expect(last_response.body).to include('Disable')
104
- expect(last_response.body).to include('Actors')
105
- expect(last_response.body).to include('Groups')
106
- expect(last_response.body).to include('Percentage of Time')
107
- expect(last_response.body).to include('Percentage of Actors')
108
112
  end
109
113
  end
110
114
 
@@ -119,12 +123,6 @@ RSpec.describe Flipper::UI::Actions::Feature do
119
123
 
120
124
  it 'renders template' do
121
125
  expect(last_response.body).to include('a/b')
122
- expect(last_response.body).to include('Enable')
123
- expect(last_response.body).to include('Disable')
124
- expect(last_response.body).to include('Actors')
125
- expect(last_response.body).to include('Groups')
126
- expect(last_response.body).to include('Percentage of Time')
127
- expect(last_response.body).to include('Percentage of Actors')
128
126
  end
129
127
  end
130
128
  end
@@ -13,19 +13,58 @@ RSpec.describe Flipper::UI::Actions::Features do
13
13
  end
14
14
 
15
15
  describe 'GET /features' do
16
- before do
17
- flipper[:stats].enable
18
- flipper[:search].enable
19
- get '/features'
20
- end
16
+ context "when there are some features" do
17
+ before do
18
+ flipper[:stats].enable
19
+ flipper[:search].enable
20
+ get '/features'
21
+ end
21
22
 
22
- it 'responds with success' do
23
- expect(last_response.status).to be(200)
23
+ it 'responds with success' do
24
+ expect(last_response.status).to be(200)
25
+ end
26
+
27
+ it 'renders template' do
28
+ expect(last_response.body).to include('stats')
29
+ expect(last_response.body).to include('search')
30
+ end
24
31
  end
25
32
 
26
- it 'renders template' do
27
- expect(last_response.body).to include('stats')
28
- expect(last_response.body).to include('search')
33
+ context "when there are no features to list" do
34
+ before do
35
+ @original_fun_enabled = Flipper::UI.configuration.fun
36
+ Flipper::UI.configuration.fun = fun_mode
37
+ end
38
+
39
+ after do
40
+ Flipper::UI.configuration.fun = @original_fun_enabled
41
+ end
42
+
43
+ context "when fun mode is enabled" do
44
+ let(:fun_mode) { true }
45
+ before { get '/features' }
46
+
47
+ it 'responds with success' do
48
+ expect(last_response.status).to be(200)
49
+ end
50
+
51
+ it 'renders template' do
52
+ expect(last_response.body).to include('And I\'ll flip your features.')
53
+ end
54
+ end
55
+
56
+ context "when fun mode is disabled" do
57
+ let(:fun_mode) { false }
58
+ before { get '/features' }
59
+
60
+ it 'responds with success' do
61
+ expect(last_response.status).to be(200)
62
+ end
63
+
64
+ it 'renders template' do
65
+ expect(last_response.body).to include('You have not added any features to configure yet.')
66
+ end
67
+ end
29
68
  end
30
69
  end
31
70
 
@@ -72,12 +111,10 @@ RSpec.describe Flipper::UI::Actions::Features do
72
111
  expect(flipper.features.map(&:key)).to eq([])
73
112
  end
74
113
 
75
- # rubocop:disable Metrics/LineLength
76
114
  it 'redirects back to feature' do
77
115
  expect(last_response.status).to be(302)
78
116
  expect(last_response.headers['Location']).to eq('/features/new?error=%22%22+is+not+a+valid+feature+name.')
79
117
  end
80
- # rubocop:enable Metrics/LineLength
81
118
  end
82
119
 
83
120
  context 'nil feature name' do
@@ -87,12 +124,10 @@ RSpec.describe Flipper::UI::Actions::Features do
87
124
  expect(flipper.features.map(&:key)).to eq([])
88
125
  end
89
126
 
90
- # rubocop:disable Metrics/LineLength
91
127
  it 'redirects back to feature' do
92
128
  expect(last_response.status).to be(302)
93
129
  expect(last_response.headers['Location']).to eq('/features/new?error=%22%22+is+not+a+valid+feature+name.')
94
130
  end
95
- # rubocop:enable Metrics/LineLength
96
131
  end
97
132
  end
98
133
  end