flipside 0.1.1 → 0.2.1
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/CHANGELOG.md +10 -1
- data/README.md +71 -4
- data/lib/flipside/config/settings.rb +7 -0
- data/lib/flipside/feature_presenter.rb +9 -1
- data/lib/flipside/version.rb +1 -1
- data/lib/flipside/views/_feature_item.erb +7 -3
- data/lib/flipside/views/index.erb +17 -12
- data/lib/flipside.rb +16 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e49af6fc8d31128f0e88089ad6d46ce1745a223a68c4f5e4f2e5353f99091073
|
4
|
+
data.tar.gz: cb1547b1c3892b363830aa5f75375998092b90f150e6a275b3224051b6eb3b19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc95be97c95f5c6285d4eb57e6b378b47277d61e43f6606eb44bf9c9c6f914a2b6019c4a143c8b9a5058c64eac6ea0f4cffbecf7138ad3836ca0dcb196515c22
|
7
|
+
data.tar.gz: fb5262d598dea36dd87e7c987ae1d263500b2bc7e39882d7da5a119a6c11aab009821d7981732a442176985054900355e6bcf2b8d2b0fa68eab99e03a6469337
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
## [
|
1
|
+
## [0.2.1] - 2025-01-30
|
2
|
+
|
3
|
+
- Option to create missing features
|
4
|
+
- Option to set link back to main application
|
5
|
+
|
6
|
+
## [0.2.0] - 2025-01-29
|
7
|
+
|
8
|
+
- Support checking multiple objects at once
|
9
|
+
- Show hover text for feature statuses
|
10
|
+
- Support feature names with spaces
|
2
11
|
|
3
12
|
## [0.1.1] - 2024-11-22
|
4
13
|
|
data/README.md
CHANGED
@@ -35,12 +35,51 @@ This will create a migration file. Run the migration, to add the flipside tables
|
|
35
35
|
|
36
36
|
1. Defining Features
|
37
37
|
|
38
|
-
|
38
|
+
Features are created by running this (in a console or from code):
|
39
39
|
```ruby
|
40
|
-
Flipside::Feature.create(
|
40
|
+
Flipside::Feature.create(
|
41
|
+
name: "MyFeature",
|
42
|
+
description: "Some optional description about what this feature do"
|
43
|
+
)
|
41
44
|
```
|
42
45
|
|
43
46
|
By default features are turned off. If you would like it turned on from the beginning you could pass in `enabled: true`.
|
47
|
+
```ruby
|
48
|
+
Flipside::Feature.create(name: "MyFeature", enabled: true)
|
49
|
+
```
|
50
|
+
|
51
|
+
Features can be active during a given period. Set `activated_at` and/or `deactivated_at` to define this period.
|
52
|
+
Note: A feature is always disabled outside of the active period.
|
53
|
+
```ruby
|
54
|
+
Flipside::Feature.create(
|
55
|
+
name: "MyFeature",
|
56
|
+
activated_at: 1.week.from_now,
|
57
|
+
deactivated_at: 2.weeks.from_now
|
58
|
+
)
|
59
|
+
```
|
60
|
+
|
61
|
+
Features can be enabled for a certain record, typically a certain user or organization. This records are called entities. To enable a feature for a given record use `.add_entity`:
|
62
|
+
```ruby
|
63
|
+
user = User.first
|
64
|
+
Flipside.enabled? user # => false
|
65
|
+
Flipside.add_entity(name: "MyFeature", user)
|
66
|
+
Flipside.enabled? user # => true
|
67
|
+
```
|
68
|
+
|
69
|
+
Features can be enabled for records responding true to a certain method. This is called a "role". Given that User records have an admin? method. A feature can then be enabled
|
70
|
+
for all users how are admins, using the `.add_role` method:
|
71
|
+
```ruby
|
72
|
+
user1 = User.new(admin: false)
|
73
|
+
user2 = User.new(admin: true)
|
74
|
+
Flipside.add_role(
|
75
|
+
name: "MyFeature",
|
76
|
+
class_name: "User",
|
77
|
+
method_name: :admin?
|
78
|
+
)
|
79
|
+
Flipside.enabled? user1 # => false
|
80
|
+
Flipside.enabled? user2 # => true
|
81
|
+
```
|
82
|
+
|
44
83
|
|
45
84
|
2. Checking Feature Status
|
46
85
|
|
@@ -54,13 +93,41 @@ Flipside.enabled? "MyFeature"
|
|
54
93
|
|
55
94
|
#### For a Specific Record
|
56
95
|
|
57
|
-
Check if a feature is enabled for a specific record (e.g. a user
|
96
|
+
Check if a feature is enabled for a specific record (e.g. a user):
|
58
97
|
|
59
98
|
```ruby
|
60
99
|
Flipside.enabled? "MyFeature", user
|
61
100
|
```
|
62
101
|
|
63
|
-
##
|
102
|
+
## UI
|
103
|
+
Flipside comes with a sinatra web ui to mange feature flags. To mount this sinatra app in Rails add the following to your routes.rb file.
|
104
|
+
```ruby
|
105
|
+
mount Flipside::Web, at: '/flipside'
|
106
|
+
```
|
107
|
+
Note: you probably want to wrap this inside a constraints block to provide some authentication.
|
108
|
+
|
109
|
+

|
110
|
+
|
111
|
+
|
112
|
+
### Configuration
|
113
|
+
|
114
|
+
Entities can be added to a feature by searching for records and adding them.
|
115
|
+

|
116
|
+
|
117
|
+
To make this work, some configuration is required. Use the class method `Flipside.register_entity` for this.
|
118
|
+
```ruby
|
119
|
+
Flipside.register_entity(
|
120
|
+
class_name: "User",
|
121
|
+
search_by: :name,
|
122
|
+
display_as: :name,
|
123
|
+
identified_by: :id
|
124
|
+
)
|
125
|
+
```
|
126
|
+
Typically this should be configured in an initializer file.
|
127
|
+
|
128
|
+
The `.register_entity` method should be called once for each class that may be used as feature enablers.
|
129
|
+
The `search_by` keyword argument, which may be a symbol or a proc, dictates how records are found from searching in the ui. When a symbol is given, then searches with an exact match on the corresponding attribute are returned. E.g. `User.where(name: query)`.
|
130
|
+
|
64
131
|
TODO
|
65
132
|
|
66
133
|
## Development
|
@@ -12,7 +12,7 @@ class FeaturePresenter
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def href
|
15
|
-
File.join(base_path, "feature", name)
|
15
|
+
File.join(base_path, "feature", ERB::Util.url_encode(name))
|
16
16
|
end
|
17
17
|
|
18
18
|
def toggle_path
|
@@ -87,6 +87,14 @@ class FeaturePresenter
|
|
87
87
|
feature.deactivated_at <= Time.now + period
|
88
88
|
end
|
89
89
|
|
90
|
+
def status_title
|
91
|
+
if activates_soon?
|
92
|
+
"Activates at: #{activated_at}"
|
93
|
+
elsif deactivates_soon?
|
94
|
+
"deactivates at: #{deactivated_at}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
90
98
|
def entity_count_str
|
91
99
|
count = feature.entities.count
|
92
100
|
if count == 1
|
data/lib/flipside/version.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
<div class="p-4 grid grid-cols-12 gap-4 cursor-pointer text-slate-300">
|
2
2
|
<div class="col-span-3 text-left text-xl"><%= feature.name %></div>
|
3
|
-
<div class="col-span-
|
4
|
-
<div class="col-span-
|
5
|
-
<span
|
3
|
+
<div class="col-span-7 text-center text-lg"><%= feature.description&.capitalize %></div>
|
4
|
+
<div class="col-span-1 text-right text-lg font-normal">
|
5
|
+
<span
|
6
|
+
class="inline-block py-1 px-2 min-w-20 text-center rounded-lg <%= feature.status_color %>"
|
7
|
+
title="<%= feature.status_title %>">
|
8
|
+
<%= feature.status %>
|
9
|
+
</span>
|
6
10
|
</div>
|
7
11
|
<div class="text-right">
|
8
12
|
<%= erb :_toggle_button, locals: {feature:} %>
|
@@ -1,15 +1,20 @@
|
|
1
|
-
<div class="
|
2
|
-
|
1
|
+
<div class="m-12">
|
2
|
+
<% if Flipside.ui_back_path %>
|
3
|
+
<a href="<%= Flipside.ui_back_path %>" class="p-2 rounded-lg text-xl text-slate-300 bg-blue-900 border border-blue-950 hover:bg-blue-800">Back</a>
|
4
|
+
<% end %>
|
5
|
+
<div class="mt-12 w-3/4 m-auto bg-gray-800 text-slate-400 p-8 pb-24 rounded-lg shadow-lg">
|
6
|
+
<h1 class="text-3xl text-center font-bold mb-6">Flipside feature flags</h1>
|
3
7
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
<div class="mt-12 m-auto">
|
9
|
+
<ul>
|
10
|
+
<% features.each do |feature| %>
|
11
|
+
<li class="border-b border-slate-500 hover:font-semibold">
|
12
|
+
<a href=<%= feature.href %>>
|
13
|
+
<%= erb :_feature_item, locals: {feature:} %>
|
14
|
+
</a>
|
15
|
+
</li>
|
16
|
+
<% end %>
|
17
|
+
</ul>
|
18
|
+
</div>
|
14
19
|
</div>
|
15
20
|
</div>
|
data/lib/flipside.rb
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
require "flipside/version"
|
4
4
|
require "flipside/web"
|
5
|
+
require "flipside/config/settings"
|
5
6
|
require "flipside/config/entities"
|
6
7
|
require "flipside/config/roles"
|
7
8
|
require "models/flipside/feature"
|
8
9
|
|
9
10
|
module Flipside
|
11
|
+
extend Config::Settings
|
10
12
|
extend Config::Entities
|
11
13
|
extend Config::Roles
|
12
14
|
|
@@ -19,11 +21,12 @@ module Flipside
|
|
19
21
|
end
|
20
22
|
|
21
23
|
class << self
|
22
|
-
def enabled?(name,
|
24
|
+
def enabled?(name, *objects)
|
23
25
|
feature = find_by(name:)
|
24
26
|
return false unless feature
|
25
27
|
|
26
|
-
|
28
|
+
objects << nil if objects.empty?
|
29
|
+
objects.any? { |object| feature.enabled? object }
|
27
30
|
end
|
28
31
|
|
29
32
|
def enable!(name)
|
@@ -51,12 +54,21 @@ module Flipside
|
|
51
54
|
feature.roles.find_by(id: role_id)&.destroy
|
52
55
|
end
|
53
56
|
|
54
|
-
def find_by(name:)
|
55
|
-
Feature.find_by(name:)
|
57
|
+
def find_by(name:, create_on_missing: create_missing_features)
|
58
|
+
feature = Feature.find_by(name:)
|
59
|
+
feature ||= create_missing(name) if create_on_missing
|
60
|
+
feature
|
56
61
|
end
|
57
62
|
|
58
63
|
def find_by!(name:)
|
59
64
|
find_by(name:) || raise(NoSuchFeauture.new(name))
|
60
65
|
end
|
66
|
+
|
67
|
+
def create_missing(name)
|
68
|
+
trace = caller.find { |trace| !trace.start_with? __FILE__ }
|
69
|
+
source, line, _ = trace.split(":")
|
70
|
+
source = [source, line].join(":") if line.match?(/\d+/)
|
71
|
+
Feature.create(name:, description: "Created from #{source}")
|
72
|
+
end
|
61
73
|
end
|
62
74
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipside
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sammy Henningsson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-01-
|
11
|
+
date: 2025-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- lib/flipside/config/registered_entity.rb
|
104
104
|
- lib/flipside/config/registered_role.rb
|
105
105
|
- lib/flipside/config/roles.rb
|
106
|
+
- lib/flipside/config/settings.rb
|
106
107
|
- lib/flipside/feature_presenter.rb
|
107
108
|
- lib/flipside/public/index.js
|
108
109
|
- lib/flipside/public/modal_controller.js
|