flipper-ui 0.21.0 → 0.22.0
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 +4 -4
- data/examples/ui/authorization.ru +11 -49
- data/examples/ui/basic.ru +10 -10
- data/lib/flipper/ui.rb +2 -2
- data/lib/flipper/ui/action.rb +1 -1
- data/lib/flipper/ui/actions/actors_gate.rb +1 -1
- data/lib/flipper/ui/actions/features.rb +2 -2
- data/lib/flipper/ui/actions/groups_gate.rb +1 -1
- data/lib/flipper/ui/actions/percentage_of_actors_gate.rb +1 -1
- data/lib/flipper/ui/actions/percentage_of_time_gate.rb +1 -1
- data/lib/flipper/ui/middleware.rb +2 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/ui/actions/actors_gate_spec.rb +19 -2
- data/spec/flipper/ui/actions/boolean_gate_spec.rb +18 -0
- data/spec/flipper/ui/actions/feature_spec.rb +18 -0
- data/spec/flipper/ui/actions/features_spec.rb +16 -3
- data/spec/flipper/ui/actions/groups_gate_spec.rb +20 -3
- data/spec/flipper/ui/actions/percentage_of_actors_gate_spec.rb +18 -1
- data/spec/flipper/ui/actions/percentage_of_time_gate_spec.rb +18 -1
- data/spec/flipper/ui_spec.rb +0 -13
- metadata +4 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 3be7bbda3ec1a09b1cc1c421766ea520a9a933eeb1628ea27281c35a174725a2
         | 
| 4 | 
            +
              data.tar.gz: ca0375faf5a0cfd4f2b6c04435c803e9414c2e41337918ad9f8bb9f95f579e46
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: effdbdd4ab7c0646dcd1a50ebd0d96fd78dc2dabb2a87ae1e524a2a4b32ce43c1b01e6e96046d1e9bc4fe298a805a2c31c713b83ad1dbfb26c31dfb70f714e90
         | 
| 7 | 
            +
              data.tar.gz: 8d1f5b3f946a0b5d9bb42db7a497484c490cc2a2e9f15562e046ddeb41be0dba1cdda19ef1016bb5f7966ab35c600b8b57418533797b3000cec927671079ff1a
         | 
| @@ -5,50 +5,13 @@ | |
| 5 5 | 
             
            #   http://localhost:9999/
         | 
| 6 6 | 
             
            #
         | 
| 7 7 | 
             
            require 'bundler/setup'
         | 
| 8 | 
            -
            require "logger"
         | 
| 9 | 
            -
             | 
| 10 8 | 
             
            require "flipper/ui"
         | 
| 11 9 | 
             
            require "flipper/adapters/pstore"
         | 
| 12 | 
            -
            require "active_support/notifications"
         | 
| 13 10 |  | 
| 14 11 | 
             
            Flipper.register(:admins) { |actor|
         | 
| 15 12 | 
             
              actor.respond_to?(:admin?) && actor.admin?
         | 
| 16 13 | 
             
            }
         | 
| 17 14 |  | 
| 18 | 
            -
            Flipper.register(:early_access) { |actor|
         | 
| 19 | 
            -
              actor.respond_to?(:early?) && actor.early?
         | 
| 20 | 
            -
            }
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            # Setup logging of flipper calls.
         | 
| 23 | 
            -
            if ENV["LOG"] == "1"
         | 
| 24 | 
            -
              $logger = Logger.new(STDOUT)
         | 
| 25 | 
            -
              require "flipper/instrumentation/log_subscriber"
         | 
| 26 | 
            -
              Flipper::Instrumentation::LogSubscriber.logger = $logger
         | 
| 27 | 
            -
            end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
            adapter = Flipper::Adapters::PStore.new
         | 
| 30 | 
            -
            flipper = Flipper.new(adapter, instrumenter: ActiveSupport::Notifications)
         | 
| 31 | 
            -
             | 
| 32 | 
            -
            Flipper::UI.configure do |config|
         | 
| 33 | 
            -
              # config.banner_text = 'Production Environment'
         | 
| 34 | 
            -
              # config.banner_class = 'danger'
         | 
| 35 | 
            -
              config.feature_creation_enabled = true
         | 
| 36 | 
            -
              config.feature_removal_enabled = true
         | 
| 37 | 
            -
              # config.show_feature_description_in_list = true
         | 
| 38 | 
            -
              config.descriptions_source = lambda do |_keys|
         | 
| 39 | 
            -
                {
         | 
| 40 | 
            -
                  "search_performance_another_long_thing" => "Just to test feature name length.",
         | 
| 41 | 
            -
                  "gauges_tracking" => "Should we track page views with gaug.es.",
         | 
| 42 | 
            -
                  "unused" => "Not used.",
         | 
| 43 | 
            -
                  "suits" => "Are suits necessary in business?",
         | 
| 44 | 
            -
                  "secrets" => "Secrets are lies.",
         | 
| 45 | 
            -
                  "logging" => "Log all the things.",
         | 
| 46 | 
            -
                  "new_cache" => "Like the old cache but newer.",
         | 
| 47 | 
            -
                  "a/b" => "Why would someone use a slash? I don't know but someone did. Let's make this really long so they regret using slashes. Please don't use slashes.",
         | 
| 48 | 
            -
                }
         | 
| 49 | 
            -
              end
         | 
| 50 | 
            -
            end
         | 
| 51 | 
            -
             | 
| 52 15 | 
             
            # Example middleware to allow reading the Flipper UI but nothing else.
         | 
| 53 16 | 
             
            class FlipperReadOnlyMiddleware
         | 
| 54 17 | 
             
              def initialize(app)
         | 
| @@ -67,18 +30,17 @@ class FlipperReadOnlyMiddleware | |
| 67 30 | 
             
            end
         | 
| 68 31 |  | 
| 69 32 | 
             
            # You can uncomment these to get some default data:
         | 
| 70 | 
            -
            #  | 
| 71 | 
            -
            #  | 
| 72 | 
            -
            #  | 
| 73 | 
            -
            #  | 
| 74 | 
            -
            #  | 
| 75 | 
            -
            #  | 
| 76 | 
            -
            #  | 
| 77 | 
            -
            #  | 
| 78 | 
            -
            #  | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
            run Flipper::UI.app(flipper) { |builder|
         | 
| 33 | 
            +
            # Flipper.enable(:search_performance_another_long_thing)
         | 
| 34 | 
            +
            # Flipper.disable(:gauges_tracking)
         | 
| 35 | 
            +
            # Flipper.disable(:unused)
         | 
| 36 | 
            +
            # Flipper.enable_actor(:suits, Flipper::Actor.new('1'))
         | 
| 37 | 
            +
            # Flipper.enable_actor(:suits, Flipper::Actor.new('6'))
         | 
| 38 | 
            +
            # Flipper.enable_group(:secrets, :admins)
         | 
| 39 | 
            +
            # Flipper.enable_percentage_of_time(:logging, 5)
         | 
| 40 | 
            +
            # Flipper.enable_percentage_of_actors(:new_cache, 15)
         | 
| 41 | 
            +
            # Flipper.add("a/b")
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            run Flipper::UI.app { |builder|
         | 
| 82 44 | 
             
              builder.use Rack::Session::Cookie, secret: "_super_secret"
         | 
| 83 45 | 
             
              builder.use FlipperReadOnlyMiddleware
         | 
| 84 46 | 
             
            }
         | 
    
        data/examples/ui/basic.ru
    CHANGED
    
    | @@ -42,16 +42,16 @@ Flipper::UI.configure do |config| | |
| 42 42 | 
             
            end
         | 
| 43 43 |  | 
| 44 44 | 
             
            # You can uncomment these to get some default data:
         | 
| 45 | 
            -
            #  | 
| 46 | 
            -
            #  | 
| 47 | 
            -
            #  | 
| 48 | 
            -
            #  | 
| 49 | 
            -
            #  | 
| 50 | 
            -
            #  | 
| 51 | 
            -
            #  | 
| 52 | 
            -
            #  | 
| 53 | 
            -
            #  | 
| 54 | 
            -
            #  | 
| 45 | 
            +
            # Flipper.enable(:search_performance_another_long_thing)
         | 
| 46 | 
            +
            # Flipper.disable(:gauges_tracking)
         | 
| 47 | 
            +
            # Flipper.disable(:unused)
         | 
| 48 | 
            +
            # Flipper.enable_actor(:suits, Flipper::Actor.new('1'))
         | 
| 49 | 
            +
            # Flipper.enable_actor(:suits, Flipper::Actor.new('6'))
         | 
| 50 | 
            +
            # Flipper.enable_group(:secrets, :admins)
         | 
| 51 | 
            +
            # Flipper.enable_group(:secrets, :early_access)
         | 
| 52 | 
            +
            # Flipper.enable_percentage_of_time(:logging, 5)
         | 
| 53 | 
            +
            # Flipper.enable_percentage_of_actors(:new_cache, 15)
         | 
| 54 | 
            +
            # Flipper.add("a/b")
         | 
| 55 55 |  | 
| 56 56 | 
             
            run Flipper::UI.app { |builder|
         | 
| 57 57 | 
             
              builder.use Rack::Session::Cookie, secret: "_super_secret"
         | 
    
        data/lib/flipper/ui.rb
    CHANGED
    
    | @@ -39,14 +39,14 @@ module Flipper | |
| 39 39 | 
             
                def self.app(flipper = nil, options = {})
         | 
| 40 40 | 
             
                  env_key = options.fetch(:env_key, 'flipper')
         | 
| 41 41 | 
             
                  rack_protection_options = options.fetch(:rack_protection, use: :authenticity_token)
         | 
| 42 | 
            +
             | 
| 42 43 | 
             
                  app = ->(_) { [200, { 'Content-Type' => 'text/html' }, ['']] }
         | 
| 43 44 | 
             
                  builder = Rack::Builder.new
         | 
| 44 45 | 
             
                  yield builder if block_given?
         | 
| 45 46 | 
             
                  builder.use Rack::Protection, rack_protection_options
         | 
| 46 47 | 
             
                  builder.use Rack::MethodOverride
         | 
| 47 48 | 
             
                  builder.use Flipper::Middleware::SetupEnv, flipper, env_key: env_key
         | 
| 48 | 
            -
                  builder.use Flipper::Middleware | 
| 49 | 
            -
                  builder.use Flipper::UI::Middleware, env_key: env_key
         | 
| 49 | 
            +
                  builder.use Flipper::UI::Middleware, flipper: flipper, env_key: env_key
         | 
| 50 50 | 
             
                  builder.run app
         | 
| 51 51 | 
             
                  klass = self
         | 
| 52 52 | 
             
                  builder.define_singleton_method(:inspect) { klass.inspect } # pretty rake routes output
         | 
    
        data/lib/flipper/ui/action.rb
    CHANGED
    
    | @@ -151,7 +151,7 @@ module Flipper | |
| 151 151 | 
             
                  # location - The String location to set the Location header to.
         | 
| 152 152 | 
             
                  def redirect_to(location)
         | 
| 153 153 | 
             
                    status 302
         | 
| 154 | 
            -
                    header 'Location', "#{script_name}#{location}"
         | 
| 154 | 
            +
                    header 'Location', "#{script_name}#{Rack::Utils.escape_path(location)}"
         | 
| 155 155 | 
             
                    halt [@code, @headers, ['']]
         | 
| 156 156 | 
             
                  end
         | 
| 157 157 |  | 
| @@ -27,7 +27,7 @@ module Flipper | |
| 27 27 | 
             
                      value = params['value'].to_s.strip
         | 
| 28 28 |  | 
| 29 29 | 
             
                      if Util.blank?(value)
         | 
| 30 | 
            -
                        error =  | 
| 30 | 
            +
                        error = "#{value.inspect} is not a valid actor value."
         | 
| 31 31 | 
             
                        redirect_to("/features/#{feature.key}/actors?error=#{error}")
         | 
| 32 32 | 
             
                      end
         | 
| 33 33 |  | 
| @@ -49,14 +49,14 @@ module Flipper | |
| 49 49 | 
             
                      value = params['value'].to_s.strip
         | 
| 50 50 |  | 
| 51 51 | 
             
                      if Util.blank?(value)
         | 
| 52 | 
            -
                        error =  | 
| 52 | 
            +
                        error = "#{value.inspect} is not a valid feature name."
         | 
| 53 53 | 
             
                        redirect_to("/features/new?error=#{error}")
         | 
| 54 54 | 
             
                      end
         | 
| 55 55 |  | 
| 56 56 | 
             
                      feature = flipper[value]
         | 
| 57 57 | 
             
                      feature.add
         | 
| 58 58 |  | 
| 59 | 
            -
                      redirect_to "/features/#{ | 
| 59 | 
            +
                      redirect_to "/features/#{value}"
         | 
| 60 60 | 
             
                    end
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 | 
             
                end
         | 
| @@ -35,7 +35,7 @@ module Flipper | |
| 35 35 |  | 
| 36 36 | 
             
                        redirect_to("/features/#{feature.key}")
         | 
| 37 37 | 
             
                      else
         | 
| 38 | 
            -
                        error =  | 
| 38 | 
            +
                        error = "The group named #{value.inspect} has not been registered."
         | 
| 39 39 | 
             
                        redirect_to("/features/#{feature.key}/groups?error=#{error}")
         | 
| 40 40 | 
             
                      end
         | 
| 41 41 | 
             
                    end
         | 
| @@ -16,7 +16,7 @@ module Flipper | |
| 16 16 | 
             
                      begin
         | 
| 17 17 | 
             
                        feature.enable_percentage_of_actors params['value']
         | 
| 18 18 | 
             
                      rescue ArgumentError => exception
         | 
| 19 | 
            -
                        error =  | 
| 19 | 
            +
                        error = "Invalid percentage of actors value: #{exception.message}"
         | 
| 20 20 | 
             
                        redirect_to("/features/#{@feature.key}?error=#{error}")
         | 
| 21 21 | 
             
                      end
         | 
| 22 22 |  | 
| @@ -16,7 +16,7 @@ module Flipper | |
| 16 16 | 
             
                      begin
         | 
| 17 17 | 
             
                        feature.enable_percentage_of_time params['value']
         | 
| 18 18 | 
             
                      rescue ArgumentError => exception
         | 
| 19 | 
            -
                        error =  | 
| 19 | 
            +
                        error = "Invalid percentage of time value: #{exception.message}"
         | 
| 20 20 | 
             
                        redirect_to("/features/#{@feature.key}?error=#{error}")
         | 
| 21 21 | 
             
                      end
         | 
| 22 22 |  | 
| @@ -12,6 +12,7 @@ module Flipper | |
| 12 12 | 
             
                  def initialize(app, options = {})
         | 
| 13 13 | 
             
                    @app = app
         | 
| 14 14 | 
             
                    @env_key = options.fetch(:env_key, 'flipper')
         | 
| 15 | 
            +
                    @flipper = options.fetch(:flipper) { Flipper }
         | 
| 15 16 |  | 
| 16 17 | 
             
                    @action_collection = ActionCollection.new
         | 
| 17 18 |  | 
| @@ -43,7 +44,7 @@ module Flipper | |
| 43 44 | 
             
                    if action_class.nil?
         | 
| 44 45 | 
             
                      @app.call(env)
         | 
| 45 46 | 
             
                    else
         | 
| 46 | 
            -
                      flipper = env.fetch(@env_key)
         | 
| 47 | 
            +
                      flipper = env.fetch(@env_key) { Flipper }
         | 
| 47 48 | 
             
                      action_class.run(flipper, request)
         | 
| 48 49 | 
             
                    end
         | 
| 49 50 | 
             
                  end
         | 
    
        data/lib/flipper/version.rb
    CHANGED
    
    
| @@ -61,6 +61,23 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do | |
| 61 61 | 
             
                    expect(last_response.headers['Location']).to eq('/features/search')
         | 
| 62 62 | 
             
                  end
         | 
| 63 63 |  | 
| 64 | 
            +
                  context "when feature name contains space" do
         | 
| 65 | 
            +
                    before do
         | 
| 66 | 
            +
                      post 'features/sp%20ace/actors',
         | 
| 67 | 
            +
                           { 'value' => value, 'operation' => 'enable', 'authenticity_token' => token },
         | 
| 68 | 
            +
                           'rack.session' => session
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    it 'adds item to members' do
         | 
| 72 | 
            +
                      expect(flipper["sp ace"].actors_value).to include('User;6')
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    it "redirects back to feature" do
         | 
| 76 | 
            +
                      expect(last_response.status).to be(302)
         | 
| 77 | 
            +
                      expect(last_response.headers['Location']).to eq('/features/sp%20ace')
         | 
| 78 | 
            +
                    end
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
             | 
| 64 81 | 
             
                  context 'value contains whitespace' do
         | 
| 65 82 | 
             
                    let(:value) { '  User;6  ' }
         | 
| 66 83 |  | 
| @@ -75,7 +92,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do | |
| 75 92 |  | 
| 76 93 | 
             
                      it 'redirects back to feature' do
         | 
| 77 94 | 
             
                        expect(last_response.status).to be(302)
         | 
| 78 | 
            -
                        expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22 | 
| 95 | 
            +
                        expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22%20is%20not%20a%20valid%20actor%20value.')
         | 
| 79 96 | 
             
                      end
         | 
| 80 97 | 
             
                    end
         | 
| 81 98 |  | 
| @@ -84,7 +101,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do | |
| 84 101 |  | 
| 85 102 | 
             
                      it 'redirects back to feature' do
         | 
| 86 103 | 
             
                        expect(last_response.status).to be(302)
         | 
| 87 | 
            -
                        expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22 | 
| 104 | 
            +
                        expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22%20is%20not%20a%20valid%20actor%20value.')
         | 
| 88 105 | 
             
                      end
         | 
| 89 106 | 
             
                    end
         | 
| 90 107 | 
             
                  end
         | 
| @@ -31,6 +31,24 @@ RSpec.describe Flipper::UI::Actions::BooleanGate do | |
| 31 31 | 
             
                  end
         | 
| 32 32 | 
             
                end
         | 
| 33 33 |  | 
| 34 | 
            +
                context "with space in feature name" do
         | 
| 35 | 
            +
                  before do
         | 
| 36 | 
            +
                    flipper.disable :search
         | 
| 37 | 
            +
                    post 'features/sp%20ace/boolean',
         | 
| 38 | 
            +
                         { 'action' => 'Enable', 'authenticity_token' => token },
         | 
| 39 | 
            +
                         'rack.session' => session
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  it 'updates feature' do
         | 
| 43 | 
            +
                    expect(flipper.enabled?("sp ace")).to be(true)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  it 'redirects back to feature' do
         | 
| 47 | 
            +
                    expect(last_response.status).to be(302)
         | 
| 48 | 
            +
                    expect(last_response.headers['Location']).to eq('/features/sp%20ace')
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 34 52 | 
             
                context 'with disable' do
         | 
| 35 53 | 
             
                  before do
         | 
| 36 54 | 
             
                    flipper.enable :search
         | 
| @@ -29,6 +29,24 @@ RSpec.describe Flipper::UI::Actions::Feature do | |
| 29 29 | 
             
                  expect(last_response.headers['Location']).to eq('/features')
         | 
| 30 30 | 
             
                end
         | 
| 31 31 |  | 
| 32 | 
            +
                context "with space in feature name" do
         | 
| 33 | 
            +
                  before do
         | 
| 34 | 
            +
                    flipper.enable "sp ace"
         | 
| 35 | 
            +
                    delete '/features/sp%20ace',
         | 
| 36 | 
            +
                           { 'authenticity_token' => token },
         | 
| 37 | 
            +
                           'rack.session' => session
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  it 'removes feature' do
         | 
| 41 | 
            +
                    expect(flipper.features.map(&:key)).not_to include('sp ace')
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  it 'redirects to features' do
         | 
| 45 | 
            +
                    expect(last_response.status).to be(302)
         | 
| 46 | 
            +
                    expect(last_response.headers['Location']).to eq('/features')
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 32 50 | 
             
                context 'when feature_removal_enabled is set to false' do
         | 
| 33 51 | 
             
                  around do |example|
         | 
| 34 52 | 
             
                    begin
         | 
| @@ -95,7 +95,7 @@ RSpec.describe Flipper::UI::Actions::Features do | |
| 95 95 | 
             
                    expect(last_response.headers['Location']).to eq('/features/notifications_next')
         | 
| 96 96 | 
             
                  end
         | 
| 97 97 |  | 
| 98 | 
            -
                  context 'feature name  | 
| 98 | 
            +
                  context 'feature name has whitespace at beginning and end' do
         | 
| 99 99 | 
             
                    let(:feature_name) { '  notifications_next   ' }
         | 
| 100 100 |  | 
| 101 101 | 
             
                    it 'adds feature without whitespace' do
         | 
| @@ -103,6 +103,19 @@ RSpec.describe Flipper::UI::Actions::Features do | |
| 103 103 | 
             
                    end
         | 
| 104 104 | 
             
                  end
         | 
| 105 105 |  | 
| 106 | 
            +
                  context 'feature name contains space' do
         | 
| 107 | 
            +
                    let(:feature_name) { 'notifications next' }
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                    it 'adds feature with space' do
         | 
| 110 | 
            +
                      expect(flipper.features.map(&:key)).to include('notifications next')
         | 
| 111 | 
            +
                    end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    it 'redirects to feature' do
         | 
| 114 | 
            +
                      expect(last_response.status).to be(302)
         | 
| 115 | 
            +
                      expect(last_response.headers['Location']).to eq('/features/notifications%20next')
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 106 119 | 
             
                  context 'for an invalid feature name' do
         | 
| 107 120 | 
             
                    context 'empty feature name' do
         | 
| 108 121 | 
             
                      let(:feature_name) { '' }
         | 
| @@ -113,7 +126,7 @@ RSpec.describe Flipper::UI::Actions::Features do | |
| 113 126 |  | 
| 114 127 | 
             
                      it 'redirects back to feature' do
         | 
| 115 128 | 
             
                        expect(last_response.status).to be(302)
         | 
| 116 | 
            -
                        expect(last_response.headers['Location']).to eq('/features/new?error=%22%22 | 
| 129 | 
            +
                        expect(last_response.headers['Location']).to eq('/features/new?error=%22%22%20is%20not%20a%20valid%20feature%20name.')
         | 
| 117 130 | 
             
                      end
         | 
| 118 131 | 
             
                    end
         | 
| 119 132 |  | 
| @@ -126,7 +139,7 @@ RSpec.describe Flipper::UI::Actions::Features do | |
| 126 139 |  | 
| 127 140 | 
             
                      it 'redirects back to feature' do
         | 
| 128 141 | 
             
                        expect(last_response.status).to be(302)
         | 
| 129 | 
            -
                        expect(last_response.headers['Location']).to eq('/features/new?error=%22%22 | 
| 142 | 
            +
                        expect(last_response.headers['Location']).to eq('/features/new?error=%22%22%20is%20not%20a%20valid%20feature%20name.')
         | 
| 130 143 | 
             
                      end
         | 
| 131 144 | 
             
                    end
         | 
| 132 145 | 
             
                  end
         | 
| @@ -60,6 +60,23 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do | |
| 60 60 | 
             
                    expect(last_response.headers['Location']).to eq('/features/search')
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 |  | 
| 63 | 
            +
                  context 'feature name contains space' do
         | 
| 64 | 
            +
                    before do
         | 
| 65 | 
            +
                      post 'features/sp%20ace/groups',
         | 
| 66 | 
            +
                           { 'value' => group_name, 'operation' => 'enable', 'authenticity_token' => token },
         | 
| 67 | 
            +
                           'rack.session' => session
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    it 'adds item to members' do
         | 
| 71 | 
            +
                      expect(flipper["sp ace"].groups_value).to include('admins')
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    it 'redirects back to feature' do
         | 
| 75 | 
            +
                      expect(last_response.status).to be(302)
         | 
| 76 | 
            +
                      expect(last_response.headers['Location']).to eq('/features/sp%20ace')
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 63 80 | 
             
                  context 'group name contains whitespace' do
         | 
| 64 81 | 
             
                    let(:group_name) { '  admins  ' }
         | 
| 65 82 |  | 
| @@ -74,7 +91,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do | |
| 74 91 |  | 
| 75 92 | 
             
                      it 'redirects back to feature' do
         | 
| 76 93 | 
             
                        expect(last_response.status).to be(302)
         | 
| 77 | 
            -
                        expect(last_response.headers['Location']).to eq('/features/search/groups?error=The | 
| 94 | 
            +
                        expect(last_response.headers['Location']).to eq('/features/search/groups?error=The%20group%20named%20%22not_here%22%20has%20not%20been%20registered.')
         | 
| 78 95 | 
             
                      end
         | 
| 79 96 | 
             
                    end
         | 
| 80 97 |  | 
| @@ -83,7 +100,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do | |
| 83 100 |  | 
| 84 101 | 
             
                      it 'redirects back to feature' do
         | 
| 85 102 | 
             
                        expect(last_response.status).to be(302)
         | 
| 86 | 
            -
                        expect(last_response.headers['Location']).to eq('/features/search/groups?error=The | 
| 103 | 
            +
                        expect(last_response.headers['Location']).to eq('/features/search/groups?error=The%20group%20named%20%22%22%20has%20not%20been%20registered.')
         | 
| 87 104 | 
             
                      end
         | 
| 88 105 | 
             
                    end
         | 
| 89 106 |  | 
| @@ -92,7 +109,7 @@ RSpec.describe Flipper::UI::Actions::GroupsGate do | |
| 92 109 |  | 
| 93 110 | 
             
                      it 'redirects back to feature' do
         | 
| 94 111 | 
             
                        expect(last_response.status).to be(302)
         | 
| 95 | 
            -
                        expect(last_response.headers['Location']).to eq('/features/search/groups?error=The | 
| 112 | 
            +
                        expect(last_response.headers['Location']).to eq('/features/search/groups?error=The%20group%20named%20%22%22%20has%20not%20been%20registered.')
         | 
| 96 113 | 
             
                      end
         | 
| 97 114 | 
             
                    end
         | 
| 98 115 | 
             
                  end
         | 
| @@ -30,6 +30,23 @@ RSpec.describe Flipper::UI::Actions::PercentageOfActorsGate do | |
| 30 30 | 
             
                  end
         | 
| 31 31 | 
             
                end
         | 
| 32 32 |  | 
| 33 | 
            +
                context 'with space in feature name' do
         | 
| 34 | 
            +
                  before do
         | 
| 35 | 
            +
                    post 'features/sp%20ace/percentage_of_actors',
         | 
| 36 | 
            +
                         { 'value' => '24', 'authenticity_token' => token },
         | 
| 37 | 
            +
                         'rack.session' => session
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  it 'enables the feature' do
         | 
| 41 | 
            +
                    expect(flipper["sp ace"].percentage_of_actors_value).to be(24)
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  it 'redirects back to feature' do
         | 
| 45 | 
            +
                    expect(last_response.status).to be(302)
         | 
| 46 | 
            +
                    expect(last_response.headers['Location']).to eq('/features/sp%20ace')
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 33 50 | 
             
                context 'with invalid value' do
         | 
| 34 51 | 
             
                  before do
         | 
| 35 52 | 
             
                    post 'features/search/percentage_of_actors',
         | 
| @@ -43,7 +60,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfActorsGate do | |
| 43 60 |  | 
| 44 61 | 
             
                  it 'redirects back to feature' do
         | 
| 45 62 | 
             
                    expect(last_response.status).to be(302)
         | 
| 46 | 
            -
                    expect(last_response.headers['Location']).to eq('/features/search?error=Invalid | 
| 63 | 
            +
                    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')
         | 
| 47 64 | 
             
                  end
         | 
| 48 65 | 
             
                end
         | 
| 49 66 | 
             
              end
         | 
| @@ -30,6 +30,23 @@ RSpec.describe Flipper::UI::Actions::PercentageOfTimeGate do | |
| 30 30 | 
             
                  end
         | 
| 31 31 | 
             
                end
         | 
| 32 32 |  | 
| 33 | 
            +
                context 'with space in feature name' do
         | 
| 34 | 
            +
                  before do
         | 
| 35 | 
            +
                    post 'features/sp%20ace/percentage_of_time',
         | 
| 36 | 
            +
                         { 'value' => '24', 'authenticity_token' => token },
         | 
| 37 | 
            +
                         'rack.session' => session
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  it 'enables the feature' do
         | 
| 41 | 
            +
                    expect(flipper["sp ace"].percentage_of_time_value).to be(24)
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  it 'redirects back to feature' do
         | 
| 45 | 
            +
                    expect(last_response.status).to be(302)
         | 
| 46 | 
            +
                    expect(last_response.headers['Location']).to eq('/features/sp%20ace')
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 33 50 | 
             
                context 'with invalid value' do
         | 
| 34 51 | 
             
                  before do
         | 
| 35 52 | 
             
                    post 'features/search/percentage_of_time',
         | 
| @@ -43,7 +60,7 @@ RSpec.describe Flipper::UI::Actions::PercentageOfTimeGate do | |
| 43 60 |  | 
| 44 61 | 
             
                  it 'redirects back to feature' do
         | 
| 45 62 | 
             
                    expect(last_response.status).to be(302)
         | 
| 46 | 
            -
                    expect(last_response.headers['Location']).to eq('/features/search?error=Invalid | 
| 63 | 
            +
                    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')
         | 
| 47 64 | 
             
                  end
         | 
| 48 65 | 
             
                end
         | 
| 49 66 | 
             
              end
         | 
    
        data/spec/flipper/ui_spec.rb
    CHANGED
    
    | @@ -24,19 +24,6 @@ RSpec.describe Flipper::UI do | |
| 24 24 | 
             
                end
         | 
| 25 25 | 
             
              end
         | 
| 26 26 |  | 
| 27 | 
            -
              describe 'Initializing middleware lazily with a block' do
         | 
| 28 | 
            -
                let(:app) do
         | 
| 29 | 
            -
                  build_app(-> { flipper })
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                it 'works' do
         | 
| 33 | 
            -
                  flipper.enable :some_great_feature
         | 
| 34 | 
            -
                  get '/features'
         | 
| 35 | 
            -
                  expect(last_response.status).to be(200)
         | 
| 36 | 
            -
                  expect(last_response.body).to include('some_great_feature')
         | 
| 37 | 
            -
                end
         | 
| 38 | 
            -
              end
         | 
| 39 | 
            -
             | 
| 40 27 | 
             
              describe 'Request method unsupported by action' do
         | 
| 41 28 | 
             
                it 'raises error' do
         | 
| 42 29 | 
             
                  expect 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: 0. | 
| 4 | 
            +
              version: 0.22.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: 2021- | 
| 11 | 
            +
            date: 2021-07-08 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: 0. | 
| 59 | 
            +
                    version: 0.22.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: 0. | 
| 66 | 
            +
                    version: 0.22.0
         | 
| 67 67 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 68 68 | 
             
              name: erubi
         | 
| 69 69 | 
             
              requirement: !ruby/object:Gem::Requirement
         |