stoplight-admin 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea092c1ab6285d75d91b6b7582c0c521304c6aa9a417067793224a4b31cbc83f
4
- data.tar.gz: d31a8c40d3adf0cf517194b3ffdb96f4c1d425d7b1655fe8d2d7717051d08104
3
+ metadata.gz: c61065004c1c254f44f10415c852818e962b82ce7d2b7e9d451bd2b998487144
4
+ data.tar.gz: 3162abbe1ad6f0e0aad93fbade2b35fae6e7df7ddfa2b61a161bc7d339da9c9e
5
5
  SHA512:
6
- metadata.gz: 3bf410421247546b33d42ba22eb4180b92027713806a8bdd55c6f93adcdf07bf5771d7a10c7ca0706e4cf55828d160fcae5da1326352ff5078b115742a28108e
7
- data.tar.gz: e8e8a55b481d9ac832206596afc412ff2f72cb127befdb6ffc0b776393c805cab25ac96fdf41f2d4df1c8ce6ceacd265cc5d98762df845c6e22cb616c1745b2a
6
+ metadata.gz: b53b0093a1ac59c7d21352a6ea0ecd7ac3de163d000ab701cf92eb19250f9fdf803cccb1df30b6bf55d721ff12a9ca25d28239ce16c223ded9e9e42f99cf72b3
7
+ data.tar.gz: e709637df523e89529e507159bff0bffc63b364539ae1e2fe7873b5525f2aded28833d9d45ee6bfc26199b58f8115c43edf0b3fcb283b68487cf444d3becbe50
data/README.md CHANGED
@@ -6,6 +6,9 @@ A simple administration interface for [stoplight][2]. Monitor the
6
6
  status, failures, and invocations of your stoplights. Change
7
7
  stoplight colors, or lock them in either red or green state.
8
8
 
9
+ The stoplight-admin version 0.4 and above is only compatible with Stoplight 4.1. If you have Stoplight version
10
+ below 4.0, use [stoplight-admin 0.3.6].
11
+
9
12
  ## Configuration
10
13
 
11
14
  This project is packaged as a Ruby gem so that you can easily embed it
@@ -32,9 +35,19 @@ example using a local Redis data store:
32
35
  ``` rb
33
36
  # app.rb
34
37
 
38
+ require 'bundler/inline'
39
+
40
+ gemfile do
41
+ source 'https://rubygems.org'
42
+
43
+ gem 'redis'
44
+ gem 'stoplight-admin'
45
+ gem 'webrick'
46
+ end
47
+
35
48
  require 'redis'
36
49
  require 'sinatra'
37
- require 'sinatra/stoplight_admin'
50
+ require 'stoplight_admin/application'
38
51
 
39
52
  redis = Redis.new(url: 'redis://localhost:6379')
40
53
  set :data_store, Stoplight::DataStore::Redis.new(redis)
@@ -65,10 +78,10 @@ Add something like this to your `config/routes.rb`:
65
78
 
66
79
  ``` rb
67
80
  require 'redis'
68
- require 'sinatra/stoplight_admin'
81
+ require 'stoplight_admin/application'
69
82
 
70
- class StoplightAdmin < Sinatra::Base
71
- register Sinatra::StoplightAdmin
83
+ class StoplightAdminApp < Sinatra::Base
84
+ register StoplightAdmin::Application
72
85
 
73
86
  redis = Redis.new # Uses REDIS_URL environment variable.
74
87
  data_store = Stoplight::DataStore::Redis.new(redis)
@@ -76,7 +89,7 @@ class StoplightAdmin < Sinatra::Base
76
89
  end
77
90
 
78
91
  Rails.application.routes.draw do
79
- mount StoplightAdmin => '/stoplights'
92
+ mount StoplightAdminApp => '/stoplights'
80
93
  end
81
94
  ```
82
95
 
@@ -93,3 +106,4 @@ Stoplight is brought to you by [@camdez][4] and [@tfausak][5] from
93
106
  [6]: https://github.com/OrgSync
94
107
  [7]: https://badge.fury.io/rb/stoplight-admin.svg
95
108
  [8]: https://rubygems.org/gems/stoplight-admin
109
+ [stoplight-admin 0.3.6]: https://github.com/bolshakov/stoplight-admin/releases/tag/v0.3.6
@@ -1,161 +1,4 @@
1
- # coding: utf-8
1
+ require "stoplight_admin/application"
2
2
 
3
- require 'haml'
4
- require 'sinatra/base'
5
- require 'sinatra/json'
6
- require 'stoplight'
7
-
8
- module Sinatra
9
- module StoplightAdmin
10
- module Helpers
11
- COLORS = [
12
- GREEN = Stoplight::Color::GREEN,
13
- YELLOW = Stoplight::Color::YELLOW,
14
- RED = Stoplight::Color::RED
15
- ].freeze
16
-
17
- def data_store
18
- return @data_store if defined?(@data_store)
19
- @data_store = Stoplight::Light.default_data_store = settings.data_store
20
- end
21
-
22
- def lights
23
- data_store
24
- .names
25
- .map { |name| light_info(name) }
26
- .sort_by { |light| light_sort_key(light) }
27
- end
28
-
29
- def light_info(light)
30
- l = Stoplight::Light.new(light) {}
31
- color = l.color
32
- failures, state = l.data_store.get_all(l)
33
-
34
- {
35
- name: light,
36
- color: color,
37
- failures: failures,
38
- locked: locked?(state)
39
- }
40
- end
41
-
42
- def light_sort_key(light)
43
- [-COLORS.index(light[:color]),
44
- light[:name]]
45
- end
46
-
47
- def locked?(state)
48
- [Stoplight::State::LOCKED_GREEN,
49
- Stoplight::State::LOCKED_RED]
50
- .include?(state)
51
- end
52
-
53
- def stat_params(ls)
54
- h = {
55
- count_red: 0, count_yellow: 0, count_green: 0,
56
- percent_red: 0, percent_yellow: 0, percent_green: 0
57
- }
58
- return h if (size = ls.size).zero?
59
-
60
- h[:count_red] = ls.count { |l| l[:color] == RED }
61
- h[:count_yellow] = ls.count { |l| l[:color] == YELLOW }
62
- h[:count_green] = size - h[:count_red] - h[:count_yellow]
63
-
64
- h[:percent_red] = (100.0 * h[:count_red] / size).ceil
65
- h[:percent_yellow] = (100.0 * h[:count_yellow] / size).ceil
66
- h[:percent_green] = 100.0 - h[:percent_red] - h[:percent_yellow]
67
-
68
- h
69
- end
70
-
71
- def lock(light)
72
- l = Stoplight::Light.new(light) {}
73
- new_state =
74
- case l.color
75
- when Stoplight::Color::GREEN
76
- Stoplight::State::LOCKED_GREEN
77
- else
78
- Stoplight::State::LOCKED_RED
79
- end
80
-
81
- data_store.set_state(l, new_state)
82
- end
83
-
84
- def unlock(light)
85
- l = Stoplight::Light.new(light) {}
86
- data_store.set_state(l, Stoplight::State::UNLOCKED)
87
- end
88
-
89
- def green(light)
90
- l = Stoplight::Light.new(light) {}
91
- if data_store.get_state(l) == Stoplight::State::LOCKED_RED
92
- new_state = Stoplight::State::LOCKED_GREEN
93
- data_store.set_state(l, new_state)
94
- end
95
-
96
- data_store.clear_failures(l)
97
- end
98
-
99
- def red(light)
100
- l = Stoplight::Light.new(light) {}
101
- data_store.set_state(l, Stoplight::State::LOCKED_RED)
102
- end
103
-
104
- def with_lights
105
- [*params[:names]]
106
- .map { |l| CGI.unescape(l) }
107
- .each { |l| yield(l) }
108
- end
109
- end
110
-
111
- def self.registered(app)
112
- app.helpers StoplightAdmin::Helpers
113
-
114
- app.set :data_store, nil
115
- app.set :views, File.join(File.dirname(__FILE__), 'views')
116
-
117
- app.get '/' do
118
- ls = lights
119
- stats = stat_params(ls)
120
-
121
- haml :index, locals: stats.merge(lights: ls)
122
- end
123
-
124
- app.get '/stats' do
125
- ls = lights
126
- stats = stat_params(ls)
127
-
128
- json({stats: stats, lights: ls})
129
- end
130
-
131
- app.post '/lock' do
132
- with_lights { |l| lock(l) }
133
- redirect to('/')
134
- end
135
-
136
- app.post '/unlock' do
137
- with_lights { |l| unlock(l) }
138
- redirect to('/')
139
- end
140
-
141
- app.post '/green' do
142
- with_lights { |l| green(l) }
143
- redirect to('/')
144
- end
145
-
146
- app.post '/red' do
147
- with_lights { |l| red(l) }
148
- redirect to('/')
149
- end
150
-
151
- app.post '/green_all' do
152
- data_store.names
153
- .reject { |l| Stoplight::Light.new(l) {}.color == Stoplight::Color::GREEN }
154
- .each { |l| green(l) }
155
- redirect to('/')
156
- end
157
- end
158
- end
159
-
160
- register StoplightAdmin
161
- end
3
+ warn "[DEPRECATED] requiring `sinatra/stoplight_admin` is deprecated. " \
4
+ "Please require `stoplight_admin/application` instead."
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Actions
5
+ # @abstract
6
+ class Action
7
+ # @!attribute lights_repository
8
+ # @return [StoplightAdmin::LightsRepository]
9
+ attr_reader :lights_repository
10
+ private :lights_repository
11
+
12
+ # @return lights_repository [StoplightAdmin::LightsRepository]
13
+ def initialize(lights_repository:)
14
+ @lights_repository = lights_repository
15
+ end
16
+
17
+ def call(params)
18
+ raise NotImplementedError
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Actions
5
+ class Home < Action
6
+ # @!attribute lights_stats
7
+ # @return [Class<StoplightAdmin::LightsStats>]
8
+ attr_reader :lights_stats
9
+ private :lights_stats
10
+
11
+ # @param lights_stats [Class<StoplightAdmin::LightsStats>]
12
+ def initialize(lights_stats:, **deps)
13
+ super(**deps)
14
+ @lights_stats = lights_stats
15
+ end
16
+
17
+ # @return [(StoplightAdmin::LightsRepository::Light)]
18
+ def call(*)
19
+ lights = lights_repository.all
20
+ stats = lights_stats.call(lights)
21
+ [lights, stats]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Actions
5
+ # This action locks light
6
+ class Lock < Action
7
+ # @param params [Hash] query parameters
8
+ # @return [void]
9
+ def call(params)
10
+ light_names(params).each do |name|
11
+ lights_repository.lock(name)
12
+ end
13
+ end
14
+
15
+ private def light_names(params)
16
+ Array(params[:names])
17
+ .map { |name| CGI.unescape(name) }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Actions
5
+ # This action locks all lights green
6
+ class LockAllGreen < Action
7
+ # @return [void]
8
+ def call(*)
9
+ lights_repository
10
+ .with_color(RED, YELLOW)
11
+ .map(&:name)
12
+ .each { |name| lights_repository.lock(name, GREEN) }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Actions
5
+ # This action locks light with the specific name green
6
+ class LockGreen < Action
7
+ # @param params [Hash] query parameters
8
+ # @return [void]
9
+ def call(params)
10
+ light_names(params).each do |name|
11
+ lights_repository.lock(name, GREEN)
12
+ end
13
+ end
14
+
15
+ private def light_names(params)
16
+ Array(params[:names])
17
+ .map { |name| CGI.unescape(name) }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Actions
5
+ # This action locks light with the specific name red
6
+ class LockRed < Action
7
+ # @param params [Hash] query parameters
8
+ # @return [void]
9
+ def call(params)
10
+ light_names(params).each do |name|
11
+ lights_repository.lock(name, RED)
12
+ end
13
+ end
14
+
15
+ private def light_names(params)
16
+ Array(params[:names])
17
+ .map { |name| CGI.unescape(name) }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Actions
5
+ class Stats < Home
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Actions
5
+ # This action unlocks light
6
+ class Unlock < Action
7
+ # @param params [Hash] query parameters
8
+ # @return [void]
9
+ def call(params)
10
+ light_names(params).each do |name|
11
+ lights_repository.unlock(name)
12
+ end
13
+ end
14
+
15
+ private def light_names(params)
16
+ Array(params[:names])
17
+ .map { |name| CGI.unescape(name) }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ module Application
5
+ module Helpers
6
+ COLORS = [
7
+ GREEN = Stoplight::Color::GREEN,
8
+ YELLOW = Stoplight::Color::YELLOW,
9
+ RED = Stoplight::Color::RED
10
+ ].freeze
11
+
12
+ def dependencies
13
+ StoplightAdmin::Dependencies.new(data_store: settings.data_store)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sinatra"
4
+ require "sinatra/base"
5
+ require "sinatra/json"
6
+ require "stoplight_admin"
7
+
8
+ module StoplightAdmin
9
+ module Application
10
+ def self.registered(app)
11
+ app.helpers Application::Helpers
12
+
13
+ app.set :data_store, nil
14
+ app.set :views, File.join(File.dirname(__FILE__), "views")
15
+
16
+ app.get "/" do
17
+ lights, stats = dependencies.home_action.call
18
+
19
+ erb :index, locals: stats.merge(lights: lights)
20
+ end
21
+
22
+ app.get "/stats" do
23
+ lights, stats = dependencies.stats_action.call
24
+
25
+ json({stats: stats, lights: lights.map(&:as_json)})
26
+ end
27
+
28
+ app.post "/lock" do
29
+ dependencies.lock_action.call(params)
30
+
31
+ redirect to("/")
32
+ end
33
+
34
+ app.post "/unlock" do
35
+ dependencies.unlock_action.call(params)
36
+
37
+ redirect to("/")
38
+ end
39
+
40
+ app.post "/green" do
41
+ dependencies.green_action.call(params)
42
+
43
+ redirect to("/")
44
+ end
45
+
46
+ app.post "/red" do
47
+ dependencies.red_action.call(params)
48
+
49
+ redirect to("/")
50
+ end
51
+
52
+ app.post "/green_all" do
53
+ dependencies.green_all_action.call
54
+
55
+ redirect to("/")
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ StoplightAdmin.loader!.eager_load
62
+
63
+ register StoplightAdmin::Application
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ class Dependencies
5
+ # @!attribute data_store
6
+ # @return [Stoplight::DataStore::Base]
7
+ attr_reader :data_store
8
+ private :data_store
9
+
10
+ # @param data_store [Stoplight::DataStore::Base]
11
+ def initialize(data_store:)
12
+ @data_store = data_store
13
+ end
14
+
15
+ # @return [StoplightAdmin::LightsRepository]
16
+ def lights_repository
17
+ StoplightAdmin::LightsRepository.new(data_store: data_store)
18
+ end
19
+
20
+ # @return [StoplightAdmin::Actions::Home]
21
+ def home_action
22
+ StoplightAdmin::Actions::Home.new(
23
+ lights_repository: lights_repository,
24
+ lights_stats: StoplightAdmin::LightsStats
25
+ )
26
+ end
27
+
28
+ # @return [StoplightAdmin::Actions::Stats]
29
+ def stats_action
30
+ StoplightAdmin::Actions::Stats.new(
31
+ lights_repository: lights_repository,
32
+ lights_stats: StoplightAdmin::LightsStats
33
+ )
34
+ end
35
+
36
+ # @return [StoplightAdmin::Actions::Lock]
37
+ def lock_action
38
+ StoplightAdmin::Actions::Lock.new(lights_repository: lights_repository)
39
+ end
40
+
41
+ # @return [StoplightAdmin::Actions::Unlock]
42
+ def unlock_action
43
+ StoplightAdmin::Actions::Unlock.new(lights_repository: lights_repository)
44
+ end
45
+
46
+ # @return [StoplightAdmin::Actions::LockGreen]
47
+ def green_action
48
+ StoplightAdmin::Actions::LockGreen.new(lights_repository: lights_repository)
49
+ end
50
+
51
+ # @return [StoplightAdmin::Actions::LockRed]
52
+ def red_action
53
+ StoplightAdmin::Actions::LockRed.new(lights_repository: lights_repository)
54
+ end
55
+
56
+ # @return [StoplightAdmin::Actions::LockAllGreen]
57
+ def green_all_action
58
+ StoplightAdmin::Actions::LockAllGreen.new(lights_repository: lights_repository)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ class LightsRepository
5
+ class Light
6
+ COLORS = [
7
+ GREEN = Stoplight::Color::GREEN,
8
+ YELLOW = Stoplight::Color::YELLOW,
9
+ RED = Stoplight::Color::RED
10
+ ].freeze
11
+
12
+ # @!attribute name
13
+ # @return [String]
14
+ attr_reader :name
15
+
16
+ # @!attribute color
17
+ # @return [String]
18
+ attr_reader :color
19
+
20
+ # @!attribute state
21
+ # @return [String]
22
+ attr_reader :state
23
+
24
+ # @!attribute failures
25
+ # @return [<Stoplight::Failure>]
26
+ attr_reader :failures
27
+
28
+ # @param name [String]
29
+ # @param color [String]
30
+ # @param state [String]
31
+ # @param failures [<Stoplight::Failure>]
32
+ def initialize(name:, color:, state:, failures:)
33
+ @name = name
34
+ @color = color
35
+ @state = state
36
+ @failures = failures
37
+ end
38
+
39
+ # @return [Boolean]
40
+ def locked?
41
+ !unlocked?
42
+ end
43
+
44
+ # @return [Boolean]
45
+ def unlocked?
46
+ state == Stoplight::State::UNLOCKED
47
+ end
48
+
49
+ def as_json
50
+ {
51
+ name: name,
52
+ color: color,
53
+ failures: failures,
54
+ locked: locked?
55
+ }
56
+ end
57
+
58
+ # @return [Array]
59
+ def default_sort_key
60
+ [-COLORS.index(color), name]
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ class LightsRepository
5
+ # @!attribute data_store
6
+ # @return [Stoplight::DataStore::Base]
7
+ attr_reader :data_store
8
+ private :data_store
9
+
10
+ # @param data_store [Stoplight::DataStore::Base]
11
+ def initialize(data_store:)
12
+ @data_store = data_store
13
+ end
14
+
15
+ # @return [<StoplightAdmin::LightsRepository::Light>]
16
+ def all
17
+ data_store
18
+ .names
19
+ .map { |name| load_light(name) }
20
+ .sort_by(&:default_sort_key)
21
+ end
22
+
23
+ # @param colors <String>] colors name
24
+ # @return [<StoplightAdmin::LightsRepository::Light>] lights with the requested colors
25
+ #
26
+ def with_color(*colors)
27
+ requested_colors = Array(colors)
28
+
29
+ all.select do |light|
30
+ requested_colors.include?(light.color)
31
+ end
32
+ end
33
+
34
+ # @param name [String] locks light by its name
35
+ # @param color [String, nil] locks to this color. When nil is given, locks to the current
36
+ # color
37
+ # @return [void]
38
+ def lock(name, color = nil)
39
+ light = build_light(name)
40
+
41
+ case color || light.color
42
+ when Stoplight::Color::GREEN
43
+ light.lock(Stoplight::Color::GREEN)
44
+ else
45
+ light.lock(Stoplight::Color::RED)
46
+ end
47
+ end
48
+
49
+ # @param name [String] unlocks light by its name
50
+ # @return [void]
51
+ def unlock(name)
52
+ build_light(name).unlock
53
+ end
54
+
55
+ private def load_light(name)
56
+ light = build_light(name)
57
+ failures, state = data_store.get_all(light)
58
+
59
+ Light.new(
60
+ name: name,
61
+ color: light.color,
62
+ state: state,
63
+ failures: failures
64
+ )
65
+ end
66
+
67
+ private def build_light(name)
68
+ Stoplight(name).with_data_store(data_store).build
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoplightAdmin
4
+ class LightsStats
5
+ EMPTY_STATS = {
6
+ count_red: 0, count_yellow: 0, count_green: 0,
7
+ percent_red: 0, percent_yellow: 0, percent_green: 0
8
+ }.freeze
9
+
10
+ # @!attribute lights
11
+ # @return [<StoplightAdmin::LightsRepository::Light>]
12
+ attr_reader :lights
13
+ private :lights
14
+
15
+ class << self
16
+ def call(lights)
17
+ new(lights).call
18
+ end
19
+ end
20
+
21
+ # @param lights [<StoplightAdmin::LightsRepository::Light>]
22
+ def initialize(lights)
23
+ @lights = lights
24
+ end
25
+
26
+ def call
27
+ return EMPTY_STATS if size.zero?
28
+
29
+ EMPTY_STATS.merge(
30
+ count_red: count_red,
31
+ count_yellow: count_yellow,
32
+ count_green: count_green,
33
+ percent_red: percent_red,
34
+ percent_yellow: percent_yellow,
35
+ percent_green: percent_green
36
+ )
37
+ end
38
+
39
+ private def count_red
40
+ count_lights(RED)
41
+ end
42
+
43
+ private def percent_red
44
+ percent_lights(RED)
45
+ end
46
+
47
+ private def count_green
48
+ count_lights(GREEN)
49
+ end
50
+
51
+ private def percent_green
52
+ percent_lights(GREEN)
53
+ end
54
+
55
+ private def count_yellow
56
+ count_lights(YELLOW)
57
+ end
58
+
59
+ private def percent_yellow
60
+ percent_lights(YELLOW)
61
+ end
62
+
63
+ private def count_lights(color)
64
+ lights.count { |l| l.color == color }
65
+ end
66
+
67
+ private def percent_lights(color)
68
+ (100 * count_lights(color).fdiv(size)).ceil
69
+ end
70
+
71
+ private def size
72
+ lights.size
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,120 @@
1
+ <div class="jumbotron hidden-xs hidden-sm">
2
+ <h1>&#x1f6a6; All of the Lights</h1>
3
+ <p>Cop lights, flashlights, spotlights, strobe lights&hellip;</p>
4
+ </div>
5
+
6
+ <div class="main">
7
+ <% if lights.empty? %>
8
+ <div class="alert alert-warning" role="alert">
9
+ <strong>No lights found.</strong>
10
+ Ensure that your Stoplight data store is properly configured and that your Stoplight blocks have been run.
11
+ </div>
12
+ <% else %>
13
+ <div class="well">
14
+ <form method="post" action="<%= url('/green_all') %>">
15
+ <button class="btn-lg btn btn-success"
16
+ type="submit"
17
+ <%= count_red + count_yellow > 0 ? nil : "disabled" %>>
18
+ Greenify All
19
+ </button>
20
+ </form>
21
+ </div>
22
+
23
+ <div class="progress">
24
+ <div class="progress-bar progress-bar-danger" style="width: <%= percent_red %>%">
25
+ <span><%= count_red %></span>
26
+ </div>
27
+ <div class="progress-bar progress-bar-warning" style="width: <%= percent_yellow %>%">
28
+ <span><%= count_yellow %></span>
29
+ </div>
30
+ <div class="progress-bar progress-bar-success" style="width: <%= percent_green %>%">
31
+ <span><%= count_green %></span>
32
+ </div>
33
+ </div>
34
+
35
+ <div class="lights">
36
+ <table class="table table-hover">
37
+ <thead class="hidden-xs">
38
+ <tr>
39
+ <th>Status</th>
40
+ <th>
41
+ <abbr title="Locked lights will not change color automatically.">Locked?</abbr>
42
+ </th>
43
+ <th>Name</th>
44
+ <th>
45
+ <abbr title="Exceptions which caused the light to turn red.">Failures</abbr>
46
+ </th>
47
+ </tr>
48
+ </thead>
49
+ <tbody>
50
+ <% lights.each do |l| %>
51
+ <tr>
52
+ <td class="indicator">
53
+ <% if l.color == GREEN %>
54
+ <form method="post" action="<%= url('/red') %>">
55
+ <input type="hidden" name="names" value="<%= ERB::Util.html_escape(l.name) %>">
56
+ <button type="submit" class="btn btn-success">
57
+ <span>G</span><span class="hidden-xs">REEN</span>
58
+ </button>
59
+ </form>
60
+ <% elsif l.color == YELLOW %>
61
+ <form method="post" action="<%= url('/green') %>">
62
+ <input type="hidden" name="names" value="<%= ERB::Util.html_escape(l.name) %>">
63
+ <button type="submit" class="btn btn-warning">
64
+ <span>Y</span><span class="hidden-xs">ELLOW</span>
65
+ </button>
66
+ </form>
67
+ <% else %>
68
+ <form method="post" action="<%= url('/green') %>">
69
+ <input type="hidden" name="names" value="<%= ERB::Util.html_escape(l.name) %>">
70
+ <button type="submit" class="btn btn-danger">
71
+ <span>R</span><span class="hidden-xs">ED</span>
72
+ </button>
73
+ </form>
74
+ <% end %>
75
+ </td>
76
+ <td class="locked">
77
+ <% if l.locked? %>
78
+ <form method="post" action="<%= url('/unlock') %>">
79
+ <input type="hidden" name="names" value="<%= ERB::Util.html_escape(l.name) %>">
80
+ <button type="submit" class="btn btn-link">
81
+ <span class="glyphicon glyphicon-lock"></span>
82
+ </button>
83
+ </form>
84
+ <% else %>
85
+ <form method="post" action="<%= url('/lock') %>">
86
+ <input type="hidden" name="names" value="<%= ERB::Util.html_escape(l.name) %>">
87
+ <button type="submit" class="btn btn-link">
88
+ <span class="glyphicon glyphicon-minus"></span>
89
+ </button>
90
+ </form>
91
+ <% end %>
92
+ </td>
93
+ <td class="name">
94
+ <%= l.name %>
95
+ </td>
96
+ <td class="failures">
97
+ <% if l.failures %>
98
+ <ul>
99
+ <% l.failures.each do |failure| %>
100
+ <li>
101
+ <span class="error">
102
+ <%= ERB::Util.html_escape(failure.error_class) %>
103
+ \:
104
+ <%= ERB::Util.html_escape(failure.error_message) %>
105
+ </span>
106
+ <span class="timestamp">
107
+ <%= ERB::Util.html_escape(failure.time) %>
108
+ </span>
109
+ </li>
110
+ <% end %>
111
+ </ul>
112
+ <% end %>
113
+ </td>
114
+ </tr>
115
+ <% end %>
116
+ </tbody>
117
+ </table>
118
+ </div>
119
+ <% end %>
120
+ </div>
@@ -0,0 +1,55 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+
7
+ <title>Stoplight Admin</title>
8
+
9
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
10
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css">
11
+ <link rel="shortcut icon" href="//i.imgur.com/qvfoNuh.png">
12
+
13
+ <style>
14
+ td.indicator {
15
+ font-size: 200%;
16
+ }
17
+
18
+ td.name {
19
+ font-weight: bold;
20
+ }
21
+
22
+ td.locked button {
23
+ font-size: 200%;
24
+ }
25
+
26
+ td.failures span.error {
27
+ font-weight: bold;
28
+ }
29
+
30
+ td.failures ul {
31
+ padding: 0;
32
+ list-style-type: none;
33
+ }
34
+
35
+ .btn-group form {
36
+ display: inline-block;
37
+ }
38
+ </style>
39
+ </head>
40
+ <body>
41
+ <div class="navbar navbar-inverse navbar-static-top" role="navigation">
42
+ <div class="container">
43
+ <div class="navbar-header">
44
+ <a class="navbar-brand" href="<%= url('/') %>">Stoplight Admin</a>
45
+ </div>
46
+ </div>
47
+ </div>
48
+
49
+ <div class="container" role="main">
50
+ <%= yield %>
51
+ </div>
52
+
53
+ <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
54
+ </body>
55
+ </html>
@@ -0,0 +1,21 @@
1
+ require "stoplight"
2
+ require "zeitwerk"
3
+
4
+ module StoplightAdmin
5
+ COLORS = [
6
+ GREEN = Stoplight::Color::GREEN,
7
+ YELLOW = Stoplight::Color::YELLOW,
8
+ RED = Stoplight::Color::RED
9
+ ].freeze
10
+
11
+ class << self
12
+ def loader!
13
+ @loader ||= Zeitwerk::Loader.for_gem.tap do |loader|
14
+ loader.ignore("#{__dir__}/sinatra")
15
+ loader.setup
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ StoplightAdmin.loader!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stoplight-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Desautels
@@ -9,36 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-02-27 00:00:00.000000000 Z
12
+ date: 2023-08-23 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: haml
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - "~>"
19
- - !ruby/object:Gem::Version
20
- version: '5.0'
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - "~>"
26
- - !ruby/object:Gem::Version
27
- version: '5.0'
28
- - !ruby/object:Gem::Dependency
29
- name: sinatra-contrib
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - "~>"
33
- - !ruby/object:Gem::Version
34
- version: 2.2.3
35
- type: :runtime
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - "~>"
40
- - !ruby/object:Gem::Version
41
- version: 2.2.3
42
14
  - !ruby/object:Gem::Dependency
43
15
  name: redis
44
16
  requirement: !ruby/object:Gem::Requirement
@@ -54,75 +26,53 @@ dependencies:
54
26
  - !ruby/object:Gem::Version
55
27
  version: '3.2'
56
28
  - !ruby/object:Gem::Dependency
57
- name: stoplight
29
+ name: zeitwerk
58
30
  requirement: !ruby/object:Gem::Requirement
59
31
  requirements:
60
32
  - - ">="
61
33
  - !ruby/object:Gem::Version
62
- version: '1.4'
34
+ version: '0'
63
35
  type: :runtime
64
36
  prerelease: false
65
37
  version_requirements: !ruby/object:Gem::Requirement
66
38
  requirements:
67
39
  - - ">="
68
40
  - !ruby/object:Gem::Version
69
- version: '1.4'
41
+ version: '0'
70
42
  - !ruby/object:Gem::Dependency
71
- name: bundler
43
+ name: sinatra-contrib
72
44
  requirement: !ruby/object:Gem::Requirement
73
45
  requirements:
74
- - - "~>"
75
- - !ruby/object:Gem::Version
76
- version: '2.4'
77
- type: :development
78
- prerelease: false
79
- version_requirements: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - "~>"
46
+ - - ">="
82
47
  - !ruby/object:Gem::Version
83
- version: '2.4'
84
- - !ruby/object:Gem::Dependency
85
- name: pry-byebug
86
- requirement: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - "~>"
48
+ version: 2.2.3
49
+ - - "<"
89
50
  - !ruby/object:Gem::Version
90
- version: 3.10.0
91
- type: :development
51
+ version: 3.2.0
52
+ type: :runtime
92
53
  prerelease: false
93
54
  version_requirements: !ruby/object:Gem::Requirement
94
55
  requirements:
95
- - - "~>"
96
- - !ruby/object:Gem::Version
97
- version: 3.10.0
98
- - !ruby/object:Gem::Dependency
99
- name: rake
100
- requirement: !ruby/object:Gem::Requirement
101
- requirements:
102
- - - "~>"
56
+ - - ">="
103
57
  - !ruby/object:Gem::Version
104
- version: '13.0'
105
- type: :development
106
- prerelease: false
107
- version_requirements: !ruby/object:Gem::Requirement
108
- requirements:
109
- - - "~>"
58
+ version: 2.2.3
59
+ - - "<"
110
60
  - !ruby/object:Gem::Version
111
- version: '13.0'
61
+ version: 3.2.0
112
62
  - !ruby/object:Gem::Dependency
113
- name: rspec
63
+ name: stoplight
114
64
  requirement: !ruby/object:Gem::Requirement
115
65
  requirements:
116
- - - "~>"
66
+ - - ">="
117
67
  - !ruby/object:Gem::Version
118
- version: 3.12.0
119
- type: :development
68
+ version: '4.1'
69
+ type: :runtime
120
70
  prerelease: false
121
71
  version_requirements: !ruby/object:Gem::Requirement
122
72
  requirements:
123
- - - "~>"
73
+ - - ">="
124
74
  - !ruby/object:Gem::Version
125
- version: 3.12.0
75
+ version: '4.1'
126
76
  description: A simple administration interface for Stoplight.
127
77
  email:
128
78
  - camdez@gmail.com
@@ -134,8 +84,23 @@ files:
134
84
  - LICENSE.md
135
85
  - README.md
136
86
  - lib/sinatra/stoplight_admin.rb
137
- - lib/sinatra/views/index.haml
138
- - lib/sinatra/views/layout.haml
87
+ - lib/stoplight_admin.rb
88
+ - lib/stoplight_admin/actions/action.rb
89
+ - lib/stoplight_admin/actions/home.rb
90
+ - lib/stoplight_admin/actions/lock.rb
91
+ - lib/stoplight_admin/actions/lock_all_green.rb
92
+ - lib/stoplight_admin/actions/lock_green.rb
93
+ - lib/stoplight_admin/actions/lock_red.rb
94
+ - lib/stoplight_admin/actions/stats.rb
95
+ - lib/stoplight_admin/actions/unlock.rb
96
+ - lib/stoplight_admin/application.rb
97
+ - lib/stoplight_admin/application/helpers.rb
98
+ - lib/stoplight_admin/dependencies.rb
99
+ - lib/stoplight_admin/lights_repository.rb
100
+ - lib/stoplight_admin/lights_repository/light.rb
101
+ - lib/stoplight_admin/lights_stats.rb
102
+ - lib/stoplight_admin/views/index.erb
103
+ - lib/stoplight_admin/views/layout.erb
139
104
  homepage: https://github.com/bolshakov/stoplight-admin
140
105
  licenses:
141
106
  - MIT
@@ -148,14 +113,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
113
  requirements:
149
114
  - - ">="
150
115
  - !ruby/object:Gem::Version
151
- version: 2.5.0
116
+ version: 3.0.0
152
117
  required_rubygems_version: !ruby/object:Gem::Requirement
153
118
  requirements:
154
119
  - - ">="
155
120
  - !ruby/object:Gem::Version
156
121
  version: '0'
157
122
  requirements: []
158
- rubygems_version: 3.3.7
123
+ rubygems_version: 3.4.18
159
124
  signing_key:
160
125
  specification_version: 4
161
126
  summary: A simple administration interface for Stoplight.
@@ -1,79 +0,0 @@
1
- .jumbotron.hidden-xs.hidden-sm
2
- %h1 &#x1f6a6; All of the Lights
3
- %p Cop lights, flashlights, spotlights, strobe lights&hellip;
4
-
5
- .main
6
- - if lights.empty?
7
- .alert.alert-warning{role: 'alert'}
8
- %strong No lights found.
9
- Ensure that your Stoplight data store is properly configured and that your Stoplight blocks have been run.
10
- - else
11
- .well
12
- %form{method: 'post', action: url('/green_all')}
13
- %button.btn-lg.btn.btn-success{type: 'submit', disabled: count_red + count_yellow > 0 ? nil : 'disabled'} Greenify All
14
-
15
- .progress
16
- .progress-bar.progress-bar-danger{style: "width: #{percent_red}%"}
17
- .span= count_red
18
- .progress-bar.progress-bar-warning{style: "width: #{percent_yellow}%"}
19
- .span= count_yellow
20
- .progress-bar.progress-bar-success{style: "width: #{percent_green}%"}
21
- .span= count_green
22
-
23
- .lights
24
- %table.table.table-hover
25
- %thead.hidden-xs
26
- %tr
27
- %th Status
28
- %th
29
- %abbr{title: 'Locked lights will not change color automatically.'} Locked?
30
- %th Name
31
- %th
32
- %abbr{title: 'Exceptions which caused the light to turn red.'} Failures
33
- %tbody
34
- - lights.each do |l|
35
- %tr
36
- %td.indicator
37
- - if l[:color] == GREEN
38
- %form{method: 'post', action: url('/red')}
39
- %input{type: 'hidden', name: 'names', value: CGI.escape(l[:name])}
40
- %button{type: 'submit', class: 'btn btn-success'}
41
- G
42
- %span.hidden-xs> REEN
43
- - elsif l[:color] == YELLOW
44
- %form{method: 'post', action: url('/green')}
45
- %input{type: 'hidden', name: 'names', value: CGI.escape(l[:name])}
46
- %button{type: 'submit', class: 'btn btn-warning'}
47
- Y
48
- %span.hidden-xs> ELLOW
49
- - else
50
- %form{method: 'post', action: url('/green')}
51
- %input{type: 'hidden', name: 'names', value: CGI.escape(l[:name])}
52
- %button{type: 'submit', class: 'btn btn-danger'}
53
- R
54
- %span.hidden-xs> ED
55
- %td.locked
56
- - if l[:locked]
57
- %form{method: 'post', action: url('/unlock')}
58
- %input{type: 'hidden', name: 'names', value: CGI.escape(l[:name])}
59
- %button{type: 'submit', class: 'btn btn-link'}
60
- %span{class: 'glyphicon glyphicon-lock'}
61
- - else
62
- %form{method: 'post', action: url('/lock')}
63
- %input{type: 'hidden', name: 'names', value: CGI.escape(l[:name])}
64
- %button{type: 'submit', class: 'btn btn-link'}
65
- %span{class: 'glyphicon glyphicon-minus'}
66
- %td.name
67
- = l[:name]
68
- %td.failures
69
- - if l[:failures]
70
- %ul
71
- - l[:failures].each do |failure|
72
- %li
73
- %span.error
74
- &= failure.error_class
75
- \:
76
- &= failure.error_message
77
- @
78
- %span.timestamp
79
- &= failure.time
@@ -1,48 +0,0 @@
1
- !!! 5
2
- %html{lang: 'en'}
3
- %head
4
- %meta{charset: 'utf-8'}
5
- %meta{name: 'viewport', content: 'width=device-width, initial-scale=1'}
6
-
7
- %title Stoplight Admin
8
-
9
- %link{rel: 'stylesheet', href: '//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css'}
10
- %link{rel: 'stylesheet', href: '//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css'}
11
- %link{rel: 'shortcut icon', href: '//i.imgur.com/qvfoNuh.png'}
12
-
13
- :css
14
- td.indicator {
15
- font-size: 200%;
16
- }
17
-
18
- td.name {
19
- font-weight: bold;
20
- }
21
-
22
- td.locked button {
23
- font-size: 200%;
24
- }
25
-
26
- td.failures span.error {
27
- font-weight: bold;
28
- }
29
-
30
- td.failures ul {
31
- padding: 0;
32
- list-style-type: none;
33
- }
34
-
35
- .btn-group form {
36
- display: inline-block;
37
- }
38
-
39
- %body
40
- .navbar.navbar-inverse.navbar-static-top{role: 'navigation'}
41
- .container
42
- .navbar-header
43
- %a{class: 'navbar-brand', href: url('/')} Stoplight Admin
44
-
45
- .container{role: 'main'}
46
- = yield
47
-
48
- %script{src: '//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js'}