flipflop 2.0.0 → 2.1.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 +8 -8
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/Gemfile +4 -0
- data/README.md +3 -0
- data/Rakefile +26 -3
- data/app/controllers/flipflop/features_controller.rb +0 -2
- data/app/models/flipflop/feature.rb +0 -1
- data/app/views/flipflop/features/index.html.erb +2 -2
- data/flipflop.gemspec +6 -3
- data/lib/flipflop/engine.rb +9 -5
- data/lib/flipflop/strategies/cookie_strategy.rb +7 -6
- data/lib/flipflop/strategies/query_string_strategy.rb +13 -2
- data/lib/flipflop/strategies/session_strategy.rb +15 -4
- data/lib/flipflop/version.rb +1 -1
- data/lib/generators/flipflop/migration/templates/create_features.rb +1 -1
- data/test/integration/app_test.rb +4 -0
- data/test/integration/dashboard_test.rb +4 -0
- data/test/unit/strategies/cookie_strategy_test.rb +10 -4
- data/test/unit/strategies/query_string_strategy_test.rb +16 -0
- data/test/unit/strategies/session_strategy_test.rb +18 -2
- metadata +3 -17
- data/app/assets/stylesheets/flipflop.scss +0 -109
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YWY3YjRjMGU0YmZlNDljMWM5YTNjYTllZmQ3MDljZTU2NDE0NTVkZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MjUzZTE3MjY4MDFmY2MxZjE0YWIwZmViYTk4NjNkZjUwMTlkYTE3NA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZTE1ZWM5ODgzZDM5NTA1MTllZGEyYTg3OWViYzAzOGE4YmZhMjFmYzg1NTZh
|
10
|
+
ZTkwOWQ0ODhhMzE3ZTI0YzIxMWQyYjI1MmFhN2ZjZWZmYjZhYmVhZGE5N2Mx
|
11
|
+
YWQzYWVkMzRkMTkxNTg1ODVhZDJmZGIzMWI3ODc0YmFjNjU2NTE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZWI4YTJhZTg5ZWQ4NWI0ZDRmNWU4MDVmYTc2MzYyN2NmZjA3Mjg5YjVmNGE0
|
14
|
+
Nzg3YWJiMDY0MjBmMjljNjIyZDAzYzhlZmQwY2E2NTAxZDVlODJmNTMwZTY1
|
15
|
+
MGJlNzVlYTE3ZmE1ZDc3MjhkY2E0ZGQ1YjgyNWRjY2MzMjgzOWI=
|
data/.travis.yml
CHANGED
@@ -40,6 +40,7 @@ notifications:
|
|
40
40
|
email: false
|
41
41
|
slack:
|
42
42
|
secure: crOO1QGnFn9T1DpVgxkukTSiN8lQq09X8WF8oi1Eoa7Liex4gzWq7f8wlIXPrRFAsNjU47fSrz+L1C6Eg068Vd2df9pkqjW0pLNeqUViJ35TzpYISTtzJrX+x3nvCQLlvS4leP6lkijlsvlu1IN0xnXadW5cmcMoEcPo4Yma1RUklwlreSRIEmJiutYKVFRw3gIZA9vsnXNEcD408mvSY/8Kuw+hmRQupODUalXDpZo1q3HH+ZPQq+/rGuJ7XRf9sBtxjpUF0G4FJZQhVP4CrLNYVBE/83rHJ6HSf6u3SlYVIMiautq0nWpVLPHUrkOPJVeVh6EPtoFeI/cehH1NyoAVvL5a39wFRBlJ4jVPWUrrnihJT/6+P6GM9PSnYogxtIoTsdrYES2FgtWGgwG5uLyw8U6bW7G7rCzQwBP7enVHWVCbDgdSSjE1Mg1I9qhRuL6pHs5des4VKk6pfD3p+BRqLmOZR2jx4v8MFwakSFqQWOMxaD0U1lfxecqSx9OkwWEhCFSnHeXeHInEhY6qKCdZZzT+beYn0xppUMPJGMTqe5+po8gL+5MxQwI8Xs/5hSve5frfmuS7UQf5BnFMOzwoThQrXCFRz58wXvcZTD9eTdVBV44Hsi5OLdYn9K58sNUhgcxGfRgdE7Gy9P7DD4fHPGakD/Tz++HuCmCUXNs=
|
43
|
+
before_deploy: rake assets:compile
|
43
44
|
deploy:
|
44
45
|
provider: rubygems
|
45
46
|
api_key:
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -75,12 +75,15 @@ The following strategies are provided:
|
|
75
75
|
* `:active_record` – Save feature settings in the database.
|
76
76
|
* `:class` – Provide the feature model. `Flipflop::Feature` by default (which uses the table `features`). Honors `default_scope` when features are resolved or switched on/off.
|
77
77
|
* `:cookie` – Save feature settings in browser cookies for the current user.
|
78
|
+
* `:prefix` – String prefix for all cookie names. Defaults to no prefix.
|
78
79
|
* `:path` – The path for which the cookies apply. Defaults to the root of the application.
|
79
80
|
* `:domain` – Cookie domain. Is `nil` by default (no specific domain). Can be `:all` to use the topmost domain. Can be an array of domains.
|
80
81
|
* `:secure` – Only set cookies if the connection is secured with TLS. Default is `false`.
|
81
82
|
* `:httponly` – Whether the cookies are accessible via scripting or only HTTP. Default is `false`.
|
82
83
|
* `:query_string` – Interpret query string parameters as features. This strategy is only used for resolving. It does not allow switching features on/off.
|
84
|
+
* `:prefix` – String prefix for all query string parameters. Defaults to no prefix.
|
83
85
|
* `:session` – Save feature settings in the current user's application session.
|
86
|
+
* `:prefix` – String prefix for all session variables. Defaults to no prefix.
|
84
87
|
* `:default` – Not strictly needed, all feature defaults will be applied if no strategies match a feature. Include this strategy to determine the order of using the default value, and to make it appear in the dashboard.
|
85
88
|
|
86
89
|
All strategies support these options, to change the appearance of the dashboard:
|
data/Rakefile
CHANGED
@@ -1,16 +1,39 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rake/testtask"
|
3
3
|
|
4
|
-
Rake::TestTask.new("test") do |test|
|
4
|
+
Rake::TestTask.new("test" => "assets:compile") do |test|
|
5
5
|
test.pattern = "test/**/*_test.rb"
|
6
6
|
end
|
7
7
|
|
8
|
-
Rake::TestTask.new("test:unit") do |test|
|
8
|
+
Rake::TestTask.new("test:unit" => "assets:compile") do |test|
|
9
9
|
test.pattern = "test/unit/**/*_test.rb"
|
10
10
|
end
|
11
11
|
|
12
|
-
Rake::TestTask.new("test:integration") do |test|
|
12
|
+
Rake::TestTask.new("test:integration" => "assets:compile") do |test|
|
13
13
|
test.pattern = "test/integration/**/*_test.rb"
|
14
14
|
end
|
15
15
|
|
16
16
|
task default: :test
|
17
|
+
|
18
|
+
namespace :assets do
|
19
|
+
stylesheets_path = "app/assets/stylesheets"
|
20
|
+
stylesheet_file = "flipflop.css"
|
21
|
+
stylesheet_path = stylesheets_path + "/" + stylesheet_file
|
22
|
+
|
23
|
+
task :compile do
|
24
|
+
require "bundler/setup"
|
25
|
+
require "flipflop"
|
26
|
+
require "sprockets"
|
27
|
+
require "bootstrap"
|
28
|
+
|
29
|
+
environment = Sprockets::Environment.new
|
30
|
+
environment.append_path stylesheets_path
|
31
|
+
environment.append_path Bootstrap.stylesheets_path
|
32
|
+
environment.css_compressor = :scss
|
33
|
+
File.write(stylesheet_path, environment[stylesheet_file])
|
34
|
+
end
|
35
|
+
|
36
|
+
task :clean do
|
37
|
+
FileUtils.rm(stylesheet_path)
|
38
|
+
end
|
39
|
+
end
|
@@ -30,13 +30,13 @@
|
|
30
30
|
<%= submit_tag "on",
|
31
31
|
type: "submit",
|
32
32
|
class: @feature_set.strategy_status(strategy, feature) == "on" ? "active" : nil,
|
33
|
-
disabled: strategy.switchable?
|
33
|
+
disabled: !strategy.switchable?
|
34
34
|
-%>
|
35
35
|
|
36
36
|
<%= submit_tag "off",
|
37
37
|
type: "submit",
|
38
38
|
class: @feature_set.strategy_status(strategy, feature) == "off" ? "active" : nil,
|
39
|
-
disabled: strategy.switchable?
|
39
|
+
disabled: !strategy.switchable?
|
40
40
|
-%>
|
41
41
|
</div>
|
42
42
|
<% end -%>
|
data/flipflop.gemspec
CHANGED
@@ -13,11 +13,14 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.description = %q{Declarative API for specifying features, switchable in declaration, database and cookies.}
|
14
14
|
s.license = "MIT"
|
15
15
|
|
16
|
+
s.add_dependency("activesupport", ">= 4.0")
|
17
|
+
if ENV["CONTINUOUS_INTEGRATION"]
|
18
|
+
s.files = `git ls-files`.split("\n").map { |f| f.sub(".scss", ".css") }
|
19
|
+
else
|
20
|
+
s.add_dependency("bootstrap", "= 4.0.0.alpha3")
|
16
21
|
s.files = `git ls-files`.split("\n")
|
22
|
+
end
|
17
23
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
24
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
25
|
s.require_paths = ["lib"]
|
20
|
-
|
21
|
-
s.add_dependency("activesupport", ">= 4.0")
|
22
|
-
s.add_dependency("bootstrap", "~> 4.0.0.alpha3")
|
23
26
|
end
|
data/lib/flipflop/engine.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Flipflop
|
2
2
|
class Engine < ::Rails::Engine
|
3
|
+
attr_accessor :rake_task_executing
|
4
|
+
|
3
5
|
isolate_namespace Flipflop
|
4
6
|
|
5
7
|
config.app_middleware.insert_after ActionDispatch::Callbacks,
|
@@ -23,16 +25,12 @@ module Flipflop
|
|
23
25
|
end
|
24
26
|
|
25
27
|
initializer "flipflop.dashboard", after: "flipflop.features_reloader" do |app|
|
28
|
+
next if rake_task_executing
|
26
29
|
if actions = config.flipflop.dashboard_access_filter
|
27
30
|
to_prepare do
|
28
31
|
Flipflop::FeaturesController.before_action(*actions)
|
29
32
|
Flipflop::StrategiesController.before_action(*actions)
|
30
33
|
end
|
31
|
-
else
|
32
|
-
unless defined?(Rails::Generators) or defined?(Rake)
|
33
|
-
warn("WARNING: You have not set `config.flipflop.dashboard_access_filter`; " +
|
34
|
-
"the Flipflop dashboard is now always public!")
|
35
|
-
end
|
36
34
|
end
|
37
35
|
end
|
38
36
|
|
@@ -41,6 +39,12 @@ module Flipflop
|
|
41
39
|
ActionController::Base.send(:include, interceptor)
|
42
40
|
end
|
43
41
|
|
42
|
+
def run_tasks_blocks(app)
|
43
|
+
# Skip initialization if we're in a rake task.
|
44
|
+
self.rake_task_executing = true
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
44
48
|
private
|
45
49
|
|
46
50
|
def feature_reloader(app)
|
@@ -10,6 +10,7 @@ module Flipflop
|
|
10
10
|
def initialize(**options)
|
11
11
|
# TODO: Support :expires as a runtime-evaluated option?
|
12
12
|
@options = options.extract!(:path, :domain, :secure, :httponly).freeze
|
13
|
+
@prefix = options.delete(:prefix).to_s.freeze
|
13
14
|
super(**options)
|
14
15
|
end
|
15
16
|
|
@@ -19,25 +20,25 @@ module Flipflop
|
|
19
20
|
|
20
21
|
def enabled?(feature)
|
21
22
|
return unless request?
|
22
|
-
return unless request.cookie_jar.has_key?(
|
23
|
-
cookie = request.cookie_jar[
|
23
|
+
return unless request.cookie_jar.has_key?(cookie_key(feature))
|
24
|
+
cookie = request.cookie_jar[cookie_key(feature)]
|
24
25
|
cookie_value = cookie.is_a?(Hash) ? cookie["value"] : cookie
|
25
26
|
cookie_value === "1"
|
26
27
|
end
|
27
28
|
|
28
29
|
def switch!(feature, enabled)
|
29
30
|
value = @options.merge(value: enabled ? "1" : "0")
|
30
|
-
request.cookie_jar[
|
31
|
+
request.cookie_jar[cookie_key(feature)] = value
|
31
32
|
end
|
32
33
|
|
33
34
|
def clear!(feature)
|
34
|
-
request.cookie_jar.delete(
|
35
|
+
request.cookie_jar.delete(cookie_key(feature), **@options)
|
35
36
|
end
|
36
37
|
|
37
38
|
protected
|
38
39
|
|
39
|
-
def
|
40
|
-
|
40
|
+
def cookie_key(feature)
|
41
|
+
@prefix + feature.to_s
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
@@ -7,10 +7,21 @@ module Flipflop
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
def initialize(**options)
|
11
|
+
@prefix = options.delete(:prefix).to_s.freeze
|
12
|
+
super(**options)
|
13
|
+
end
|
14
|
+
|
10
15
|
def enabled?(feature)
|
11
16
|
return unless request?
|
12
|
-
return unless request.params.has_key?(feature)
|
13
|
-
request.params[feature].to_s != "0"
|
17
|
+
return unless request.params.has_key?(param_key(feature))
|
18
|
+
request.params[param_key(feature)].to_s != "0"
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def param_key(feature)
|
24
|
+
@prefix + feature.to_s
|
14
25
|
end
|
15
26
|
end
|
16
27
|
end
|
@@ -7,22 +7,33 @@ module Flipflop
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
def initialize(**options)
|
11
|
+
@prefix = options.delete(:prefix).to_s.freeze
|
12
|
+
super(**options)
|
13
|
+
end
|
14
|
+
|
10
15
|
def switchable?
|
11
16
|
request?
|
12
17
|
end
|
13
18
|
|
14
19
|
def enabled?(feature)
|
15
20
|
return unless request?
|
16
|
-
return unless request.session.has_key?(feature)
|
17
|
-
request.session[feature]
|
21
|
+
return unless request.session.has_key?(variable_key(feature))
|
22
|
+
request.session[variable_key(feature)] == true
|
18
23
|
end
|
19
24
|
|
20
25
|
def switch!(feature, enabled)
|
21
|
-
request.session[feature] = enabled
|
26
|
+
request.session[variable_key(feature)] = enabled
|
22
27
|
end
|
23
28
|
|
24
29
|
def clear!(feature)
|
25
|
-
request.session.delete(feature)
|
30
|
+
request.session.delete(variable_key(feature))
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def variable_key(feature)
|
36
|
+
@prefix + feature.to_s
|
26
37
|
end
|
27
38
|
end
|
28
39
|
end
|
data/lib/flipflop/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class CreateFeatures < ActiveRecord::Migration<%= Rails.version >= "5" ? "[#{ActiveRecord::Migration.current_version}]" : "" %>
|
2
2
|
def change
|
3
|
-
create_table :
|
3
|
+
create_table :flipflop_features do |t|
|
4
4
|
t.string :key, null: false
|
5
5
|
t.boolean :enabled, null: false, default: false
|
6
6
|
|
@@ -9,6 +9,10 @@ describe Flipflop do
|
|
9
9
|
@app
|
10
10
|
end
|
11
11
|
|
12
|
+
after do
|
13
|
+
Flipflop::Strategies::AbstractStrategy::RequestInterceptor.request = nil
|
14
|
+
end
|
15
|
+
|
12
16
|
describe "middleware" do
|
13
17
|
it "should include cache middleware" do
|
14
18
|
middlewares = Rails.application.middleware.map(&:klass)
|
@@ -33,7 +33,7 @@ describe Flipflop::Strategies::CookieStrategy do
|
|
33
33
|
|
34
34
|
describe "with enabled feature" do
|
35
35
|
before do
|
36
|
-
subject.send(:request).cookie_jar[
|
36
|
+
subject.send(:request).cookie_jar["one"] = "1"
|
37
37
|
end
|
38
38
|
|
39
39
|
it "should have feature enabled" do
|
@@ -53,7 +53,7 @@ describe Flipflop::Strategies::CookieStrategy do
|
|
53
53
|
|
54
54
|
describe "with disabled feature" do
|
55
55
|
before do
|
56
|
-
subject.send(:request).cookie_jar[
|
56
|
+
subject.send(:request).cookie_jar["two"] = "0"
|
57
57
|
end
|
58
58
|
|
59
59
|
it "should not have feature enabled" do
|
@@ -88,13 +88,19 @@ describe Flipflop::Strategies::CookieStrategy do
|
|
88
88
|
domain: :all,
|
89
89
|
path: "/foo",
|
90
90
|
httponly: true,
|
91
|
+
prefix: :my_cookie_,
|
91
92
|
).freeze
|
92
93
|
end
|
93
94
|
|
95
|
+
it "should use prefix to resolve parameters" do
|
96
|
+
subject.send(:request).cookie_jar["my_cookie_one"] = "1"
|
97
|
+
assert_equal true, subject.enabled?(:one)
|
98
|
+
end
|
99
|
+
|
94
100
|
it "should pass options when setting value" do
|
95
101
|
subject.switch!(:one, true)
|
96
102
|
subject.send(:request).cookie_jar.write(headers = {})
|
97
|
-
assert_equal "
|
103
|
+
assert_equal "my_cookie_one=1; domain=.example.com; path=/foo; HttpOnly",
|
98
104
|
headers["Set-Cookie"]
|
99
105
|
end
|
100
106
|
|
@@ -102,7 +108,7 @@ describe Flipflop::Strategies::CookieStrategy do
|
|
102
108
|
subject.switch!(:one, true)
|
103
109
|
subject.clear!(:one)
|
104
110
|
subject.send(:request).cookie_jar.write(headers = {})
|
105
|
-
assert_equal "
|
111
|
+
assert_equal "my_cookie_one=; domain=.example.com; path=/foo; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000; HttpOnly",
|
106
112
|
headers["Set-Cookie"]
|
107
113
|
end
|
108
114
|
end
|
@@ -56,6 +56,22 @@ describe Flipflop::Strategies::QueryStringStrategy do
|
|
56
56
|
assert_nil subject.enabled?(:three)
|
57
57
|
end
|
58
58
|
end
|
59
|
+
|
60
|
+
describe "with options" do
|
61
|
+
subject do
|
62
|
+
Flipflop::Strategies::QueryStringStrategy.new(
|
63
|
+
prefix: :my_feature_,
|
64
|
+
).freeze
|
65
|
+
end
|
66
|
+
|
67
|
+
before do
|
68
|
+
subject.send(:request).params[:my_feature_one] = "1"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should use prefix to resolve parameters" do
|
72
|
+
assert_equal true, subject.enabled?(:one)
|
73
|
+
end
|
74
|
+
end
|
59
75
|
end
|
60
76
|
|
61
77
|
describe "outside request context" do
|
@@ -33,7 +33,7 @@ describe Flipflop::Strategies::SessionStrategy do
|
|
33
33
|
|
34
34
|
describe "with enabled feature" do
|
35
35
|
before do
|
36
|
-
subject.send(:request).session[
|
36
|
+
subject.send(:request).session["one"] = true
|
37
37
|
end
|
38
38
|
|
39
39
|
it "should have feature enabled" do
|
@@ -53,7 +53,7 @@ describe Flipflop::Strategies::SessionStrategy do
|
|
53
53
|
|
54
54
|
describe "with disabled feature" do
|
55
55
|
before do
|
56
|
-
subject.send(:request).session[
|
56
|
+
subject.send(:request).session["two"] = false
|
57
57
|
end
|
58
58
|
|
59
59
|
it "should not have feature enabled" do
|
@@ -81,6 +81,22 @@ describe Flipflop::Strategies::SessionStrategy do
|
|
81
81
|
assert_equal true, subject.enabled?(:three)
|
82
82
|
end
|
83
83
|
end
|
84
|
+
|
85
|
+
describe "with options" do
|
86
|
+
subject do
|
87
|
+
Flipflop::Strategies::SessionStrategy.new(
|
88
|
+
prefix: :my_feature_,
|
89
|
+
).freeze
|
90
|
+
end
|
91
|
+
|
92
|
+
before do
|
93
|
+
subject.send(:request).session["my_feature_one"] = true
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should use prefix to resolve parameters" do
|
97
|
+
assert_equal true, subject.enabled?(:one)
|
98
|
+
end
|
99
|
+
end
|
84
100
|
end
|
85
101
|
|
86
102
|
describe "outside request context" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipflop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Annesley
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-03-
|
13
|
+
date: 2016-03-18 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -26,20 +26,6 @@ dependencies:
|
|
26
26
|
- - ! '>='
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '4.0'
|
29
|
-
- !ruby/object:Gem::Dependency
|
30
|
-
name: bootstrap
|
31
|
-
requirement: !ruby/object:Gem::Requirement
|
32
|
-
requirements:
|
33
|
-
- - ~>
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
-
version: 4.0.0.alpha3
|
36
|
-
type: :runtime
|
37
|
-
prerelease: false
|
38
|
-
version_requirements: !ruby/object:Gem::Requirement
|
39
|
-
requirements:
|
40
|
-
- - ~>
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: 4.0.0.alpha3
|
43
29
|
description: Declarative API for specifying features, switchable in declaration, database
|
44
30
|
and cookies.
|
45
31
|
email:
|
@@ -56,7 +42,7 @@ files:
|
|
56
42
|
- LICENSE
|
57
43
|
- README.md
|
58
44
|
- Rakefile
|
59
|
-
- app/assets/stylesheets/flipflop.
|
45
|
+
- app/assets/stylesheets/flipflop.css
|
60
46
|
- app/controllers/concerns/flipflop/environment_filters.rb
|
61
47
|
- app/controllers/flipflop/features_controller.rb
|
62
48
|
- app/controllers/flipflop/strategies_controller.rb
|
@@ -1,109 +0,0 @@
|
|
1
|
-
$enable-transitions: true;
|
2
|
-
@import "bootstrap";
|
3
|
-
|
4
|
-
section.flipflop {
|
5
|
-
@extend .container-fluid;
|
6
|
-
margin: 5rem 0 0;
|
7
|
-
|
8
|
-
table {
|
9
|
-
@extend .table;
|
10
|
-
@extend .table-striped;
|
11
|
-
|
12
|
-
thead {
|
13
|
-
@extend .thead-inverse;
|
14
|
-
|
15
|
-
th {
|
16
|
-
position: relative;
|
17
|
-
cursor: default;
|
18
|
-
|
19
|
-
&[data-tooltip]:before, &[data-tooltip]:after {
|
20
|
-
@include transition(all 0.2s ease-out);
|
21
|
-
transform: translateY(0.2rem) translateZ(0);
|
22
|
-
opacity: 0;
|
23
|
-
|
24
|
-
display: block;
|
25
|
-
position: absolute;
|
26
|
-
}
|
27
|
-
|
28
|
-
&[data-tooltip]:before {
|
29
|
-
content: attr(data-tooltip);
|
30
|
-
width: 98%;
|
31
|
-
left: 0;
|
32
|
-
bottom: 3.75rem;
|
33
|
-
margin: 0;
|
34
|
-
padding: 0.5rem 0.75rem;
|
35
|
-
background: $gray;
|
36
|
-
border-radius: 0.2rem;
|
37
|
-
font-size: 0.875rem;
|
38
|
-
font-weight: normal;
|
39
|
-
pointer-events: none;
|
40
|
-
}
|
41
|
-
|
42
|
-
&[data-tooltip]:after {
|
43
|
-
content: " ";
|
44
|
-
width: 0;
|
45
|
-
height: 0;
|
46
|
-
left: 1rem;
|
47
|
-
bottom: 3.25rem;
|
48
|
-
border-left: solid transparent 0.5rem;
|
49
|
-
border-right: solid transparent 0.5rem;
|
50
|
-
border-top: solid $gray 0.5rem;
|
51
|
-
}
|
52
|
-
|
53
|
-
&:hover {
|
54
|
-
&[data-tooltip]:before, &[data-tooltip]:after {
|
55
|
-
transform: translateY(0) translateZ(0);
|
56
|
-
opacity: 1;
|
57
|
-
}
|
58
|
-
}
|
59
|
-
}
|
60
|
-
}
|
61
|
-
|
62
|
-
tbody {
|
63
|
-
td.status {
|
64
|
-
width: 2rem;
|
65
|
-
font-size: 1.1rem;
|
66
|
-
|
67
|
-
span {
|
68
|
-
width: 2rem;
|
69
|
-
@extend .label;
|
70
|
-
@extend .label-pill;
|
71
|
-
&.on { @extend .label-success; }
|
72
|
-
&.off { @extend .label-default; }
|
73
|
-
}
|
74
|
-
}
|
75
|
-
|
76
|
-
td.name {
|
77
|
-
min-width: 11rem;
|
78
|
-
padding-top: 0.9rem;
|
79
|
-
font-weight: bold;
|
80
|
-
}
|
81
|
-
|
82
|
-
td.description {
|
83
|
-
min-width: 11rem;
|
84
|
-
padding-top: 0.9rem;
|
85
|
-
}
|
86
|
-
|
87
|
-
td.toggle {
|
88
|
-
min-width: 11rem;
|
89
|
-
|
90
|
-
div.toolbar {
|
91
|
-
@extend .btn-toolbar;
|
92
|
-
margin-left: 0;
|
93
|
-
|
94
|
-
div.group {
|
95
|
-
@extend .btn-group;
|
96
|
-
@extend .btn-group-sm;
|
97
|
-
|
98
|
-
input[type=submit] {
|
99
|
-
@extend .btn;
|
100
|
-
@extend .btn-sm;
|
101
|
-
&.active { @extend .btn-primary; }
|
102
|
-
&:not(.active) { @extend .btn-secondary; }
|
103
|
-
}
|
104
|
-
}
|
105
|
-
}
|
106
|
-
}
|
107
|
-
}
|
108
|
-
}
|
109
|
-
}
|