stoplight 6.0.0 → 6.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9e835f7351f236b8965d8179da39eff4eaf768bbf066c94cb35f8ed6f0360f6
4
- data.tar.gz: ea64aa21f4874b40843e2f18716da346b4e0a4fbf77f57ca777bafa8e396ae5b
3
+ metadata.gz: 7c2fb11cc6efb02fa6c4dd2a6f5c83adcd5f98ee33fd2adb7ba5c8b960ec4655
4
+ data.tar.gz: 3a5ef6988bd7bcb8e98aa4a7bd2d9396a9bac114c0c9de9ad7e2f94ba37caca5
5
5
  SHA512:
6
- metadata.gz: 3bfa3fb97ed1f8f2743930257fefb4eba4f380b9b7eea122af9ca792206b43c27b42fb35292d95ab6c608ad70e3f99f6cf3ca0eb319e2d31c2010943e50a9730
7
- data.tar.gz: 330fce49dcde86b0d0a9864143523db53caa20f64105cd40f85fcc4930769e3cd35ddb1f199aefce184b6c08eed69259acf0d697a9c4dc4e8245f482fc4a2474
6
+ metadata.gz: a7bb11404866fc8c14379e3aa94da53aff011e66b86cf2dd582b451b72a61b41f271a375523a585c21d5f54750f37c5cc38ac72fe11a889690eb99b2a46c82a5
7
+ data.tar.gz: 5c2691111ce274ee61de5632200c77482bc885e0fc1f6d01a90bc329ad25cae57dda2fcf4c4264469c736d9d19e86c2a0b8dd3200efa3a755e0e5c3961f14893
data/LICENSE.md CHANGED
@@ -1,6 +1,7 @@
1
1
  The MIT License (MIT)
2
2
 
3
3
  Copyright (c) 2015-2016 Cameron Desautels, Taylor Fausak & Justin Steffy
4
+
4
5
  Copyright (c) 2019-2026 Tëma Bolshakov, George Asfour and contributors
5
6
 
6
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -0,0 +1,107 @@
1
+ .panel-page {
2
+ height: 100vh;
3
+ display: flex;
4
+ flex-direction: column;
5
+ }
6
+
7
+ .panel-empty {
8
+ padding: 6rem 2rem;
9
+ }
10
+
11
+ .panel-main {
12
+ flex: 1;
13
+ min-height: 0;
14
+ }
15
+
16
+ .light-card {
17
+ grid-template-columns: 300px 1fr;
18
+ }
19
+
20
+ .light-pane {
21
+ min-height: 0;
22
+ }
23
+
24
+ .light-detail-pane {
25
+ padding: 26px 28px;
26
+ }
27
+
28
+ .light-detail-grid {
29
+ grid-template-columns: 40px 1fr;
30
+ column-gap: 12px;
31
+ }
32
+
33
+ .light-detail-avatar {
34
+ grid-row: span 2;
35
+ align-self: center;
36
+ }
37
+
38
+ .light-detail-name {
39
+ grid-column: 2;
40
+ }
41
+
42
+ .light-detail-status {
43
+ grid-column: 2;
44
+ }
45
+
46
+ .light-detail-card {
47
+ grid-column: 1 / -1;
48
+ }
49
+
50
+ .light-frame {
51
+ display: block;
52
+ height: 100%;
53
+ }
54
+
55
+ .light-row {
56
+ padding: 9px 14px;
57
+ min-height: 52px;
58
+ border-left: 3px solid transparent;
59
+ }
60
+
61
+ .light-row:hover {
62
+ background-color: var(--color-gray-50);
63
+ }
64
+
65
+ .light-row[aria-current="page"] {
66
+ background-color: #fff;
67
+ }
68
+
69
+ .light-row[aria-current="page"] .light-row-name {
70
+ font-weight: 600;
71
+ }
72
+
73
+ li[data-color="green"] .light-row[aria-current="page"] {
74
+ border-left-color: var(--color-green-600);
75
+ }
76
+
77
+ li[data-color="yellow"] .light-row[aria-current="page"] {
78
+ border-left-color: var(--color-yellow-600);
79
+ }
80
+
81
+ li[data-color="red"] .light-row[aria-current="page"] {
82
+ border-left-color: var(--color-red-600);
83
+ }
84
+
85
+ .light-detail-message {
86
+ font-family: ui-monospace, Menlo, monospace;
87
+ }
88
+
89
+ .text-yellow-600 {
90
+ color: var(--color-yellow-600);
91
+ }
92
+
93
+ .text-yellow-900 {
94
+ color: var(--color-yellow-900);
95
+ }
96
+
97
+ .border-green-100 {
98
+ border-color: var(--color-green-100);
99
+ }
100
+
101
+ .w-2\.5 {
102
+ width: calc(var(--spacing) * 2.5);
103
+ }
104
+
105
+ .h-2\.5 {
106
+ height: calc(var(--spacing) * 2.5);
107
+ }
@@ -18,11 +18,11 @@ module Stoplight
18
18
  end
19
19
 
20
20
  def system_url(system_id, path)
21
- url("/systems/#{system_id}#{path}")
21
+ url("/systems/#{system_id}#{path}", false)
22
22
  end
23
23
 
24
24
  def asset_path(name)
25
- url("/#{name}?v=#{ASSET_DIGESTS.fetch(name)}")
25
+ url("/#{name}?v=#{ASSET_DIGESTS.fetch(name)}", false)
26
26
  end
27
27
 
28
28
  # A read-only control keeps its place but loses its href, so there is nothing to follow
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ class Admin
5
+ class Panel
6
+ module Actions
7
+ class LightList
8
+ COLORS = [
9
+ Stoplight::Color::GREEN,
10
+ Stoplight::Color::YELLOW,
11
+ Stoplight::Color::RED
12
+ ].freeze
13
+
14
+ def initialize(config_registry:, storage:)
15
+ @config_registry = config_registry
16
+ @storage = storage
17
+ end
18
+
19
+ def call
20
+ @config_registry.all.map { |config| build_light(config) }.sort_by { |light| sort_key(light) }
21
+ end
22
+
23
+ private def build_light(config)
24
+ state_snapshot = @storage.state_snapshot(config)
25
+
26
+ LightSummary.new(
27
+ id: config.id,
28
+ name: config.name,
29
+ color: state_snapshot.color,
30
+ lock_state: state_snapshot.locked_state
31
+ )
32
+ end
33
+
34
+ private def sort_key(light)
35
+ [-COLORS.index(light.color).to_i, light.name]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ class Admin
5
+ class Panel
6
+ class Dependencies
7
+ def initialize(system:)
8
+ @system = system
9
+ @storage = @system.__stoplight__storage
10
+ end
11
+
12
+ def config_registry
13
+ ConfigRegistry.new(
14
+ registry: @system.__stoplight__registry,
15
+ system_config: @system.config
16
+ )
17
+ end
18
+
19
+ def light_list_action
20
+ Actions::LightList.new(
21
+ config_registry: config_registry,
22
+ storage: @storage
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ class Admin
5
+ class Panel
6
+ module Helpers
7
+ STATE_TEMPLATES = {
8
+ [Stoplight::Color::GREEN, Stoplight::State::UNLOCKED] => :"states/_green",
9
+ [Stoplight::Color::GREEN, Stoplight::State::LOCKED_GREEN] => :"states/_locked_green",
10
+ [Stoplight::Color::YELLOW, Stoplight::State::UNLOCKED] => :"states/_yellow",
11
+ [Stoplight::Color::RED, Stoplight::State::UNLOCKED] => :"states/_red",
12
+ [Stoplight::Color::RED, Stoplight::State::LOCKED_RED] => :"states/_locked_red"
13
+ }.freeze
14
+
15
+ def dependencies
16
+ Dependencies.new(system: current_system)
17
+ end
18
+
19
+ def selected_light(lights)
20
+ lights.first
21
+ end
22
+
23
+ def find_light(lights, light_id)
24
+ lights.find(-> { halt 404 }) { |light| light.id == light_id }
25
+ end
26
+
27
+ def state_template_for(light)
28
+ STATE_TEMPLATES.fetch([light.color, light.lock_state])
29
+ end
30
+
31
+ def system_url(system_id, path)
32
+ url("/systems/#{system_id}#{path}", false)
33
+ end
34
+
35
+ def asset_path(name)
36
+ url("/#{name}?v=#{ASSET_DIGESTS.fetch(name)}", false)
37
+ end
38
+
39
+ def find_system(system_id)
40
+ settings.systems.find(-> { halt 404 }) do |system|
41
+ system.config.id == system_id
42
+ end
43
+ end
44
+
45
+ def current_system_id
46
+ T.must(params[:system_id])
47
+ end
48
+
49
+ def current_system
50
+ find_system(current_system_id)
51
+ end
52
+
53
+ def turbo_frame_request?
54
+ !!request.env["HTTP_TURBO_FRAME"]
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ class Admin
5
+ class Panel
6
+ LightSummary = Data.define(:id, :name, :color, :lock_state)
7
+
8
+ class LightSummary
9
+ def locked? = lock_state != Stoplight::State::UNLOCKED
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ <section data-role="empty-state" class="panel-empty flex flex-col items-center justify-center text-center">
2
+ <div class="flex items-center justify-center w-16 h-16 mb-6 rounded-full bg-blue-50">
3
+ <svg class="w-8 h-8 text-blue-600" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
4
+ <path d="m19 5 3-3"/><path d="m2 22 3-3"/><path d="M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z"/><path d="M7.5 13.5 10 11"/><path d="M10.5 16.5 13 14"/><path d="m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z"/>
5
+ </svg>
6
+ </div>
7
+
8
+ <h2 class="text-4xl leading-none font-semibold tracking-tight">No lights found</h2>
9
+
10
+ <p class="max-w-2xl mt-5 text-lg text-gray-500">
11
+ Ensure lights are registered and this Admin instance uses the same data store as your application.
12
+ </p>
13
+
14
+ <a href="<%= system_url(current_system_id, "/lights") %>" class="inline-flex items-center gap-2 mt-7 px-5 py-3 font-medium text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:ring-blue-300">
15
+ <svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
16
+ <path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"/><path d="M16 16h5v5"/>
17
+ </svg>
18
+ Refresh Lights
19
+ </a>
20
+ </section>
@@ -0,0 +1,24 @@
1
+ <div data-role="light-detail" data-light="<%= CGI.escapeHTML(light.name) %>">
2
+ <div class="light-detail-grid grid">
3
+ <div class="light-detail-avatar relative w-10 h-10">
4
+ <div class="inline-flex items-center justify-center w-10 h-10 rounded-full text-sm font-medium bg-<%= light.color %>-100 text-<%= light.color %>-600">
5
+ <%= CGI.escapeHTML(light.name[0].to_s.upcase) %>
6
+ </div>
7
+ <div class="absolute bottom-0 right-0 inline-flex items-center justify-center w-4 h-4 bg-white border-2 border-white rounded-full">
8
+ <% if light.locked? %>
9
+ <svg aria-hidden="true" class="w-3 h-3 text-<%= light.color %>-900" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
10
+ <circle cx="12" cy="16" r="1"/><rect x="3" y="10" width="18" height="12" rx="2"/><path d="M7 10V7a5 5 0 0 1 10 0v3"/>
11
+ </svg>
12
+ <% else %>
13
+ <svg aria-hidden="true" class="w-3 h-3 text-<%= light.color %>-900" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
14
+ <circle cx="12" cy="16" r="1"/><rect x="3" y="10" width="18" height="12" rx="2"/><path d="M7 10V7a5 5 0 0 1 9.33-2.5"/>
15
+ </svg>
16
+ <% end %>
17
+ </div>
18
+ </div>
19
+
20
+ <h2 class="light-detail-name min-w-0 truncate text-xl font-semibold"><%= CGI.escapeHTML(light.name) %></h2>
21
+
22
+ <%= erb state_template_for(light), locals: {light: light} %>
23
+ </div>
24
+ </div>
@@ -0,0 +1,29 @@
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="icon" href="<%= asset_path("favicon.ico") %>" sizes="32x32">
10
+ <link rel="icon" href="<%= asset_path("icon.svg") %>" type="image/svg+xml">
11
+ <link rel="apple-touch-icon" href="<%= asset_path("apple-touch-icon.png") %>">
12
+
13
+ <script nonce="<%= settings.nonce(request) %>" type="module" src="<%= asset_path("turbo.es2017-esm.min.js") %>"></script>
14
+ <link rel="stylesheet" href="<%= asset_path("flowbite.min.css") %>">
15
+ <link rel="stylesheet" href="<%= asset_path("panel.css") %>">
16
+ </head>
17
+ <body class="panel-page bg-gray-50 text-gray-900 antialiased">
18
+ <header class="flex flex-wrap items-center justify-between p-4 bg-white border-b border-gray-200">
19
+ <a href="<%= url("/", false) %>" class="flex items-center gap-3">
20
+ <span class="text-2xl" aria-hidden="true">🚦</span>
21
+ <span class="text-2xl font-semibold whitespace-nowrap">Stoplight Admin</span>
22
+ </a>
23
+ </header>
24
+
25
+ <main class="panel-main">
26
+ <%= yield %>
27
+ </main>
28
+ </body>
29
+ </html>
@@ -0,0 +1,36 @@
1
+ <% if lights.empty? %>
2
+ <%= erb :_empty %>
3
+ <% else %>
4
+ <turbo-frame id="light-detail" class="light-frame">
5
+ <div class="light-card grid bg-white border border-gray-200 h-full">
6
+ <div class="light-pane bg-gray-50 border-r border-gray-200 overflow-y-auto">
7
+ <nav aria-label="Lights">
8
+ <ul data-role="light-list">
9
+ <% lights.each do |light| %>
10
+ <li data-role="light-row" data-light="<%= CGI.escapeHTML(light.name) %>" data-color="<%= light.color %>" data-locked="<%= light.locked? %>">
11
+ <a
12
+ href="<%= system_url(current_system_id, "/lights/#{CGI.escapeHTML(light.id)}") %>"
13
+ data-turbo-action="advance"
14
+ <% if light.id == selected_light.id %>aria-current="page"<% end %>
15
+ class="light-row flex items-center gap-2 text-sm border-b border-gray-100"
16
+ >
17
+ <span role="img" aria-label="<%= light.color %>" class="w-2 h-2 rounded-full shrink-0 bg-<%= light.color %>-600"></span>
18
+ <span class="light-row-name flex-1 min-w-0 truncate"><%= CGI.escapeHTML(light.name) %></span>
19
+ <% if light.locked? %>
20
+ <svg data-role="lock-icon" role="img" aria-label="Locked" class="w-3 h-3 shrink-0 text-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
21
+ <circle cx="12" cy="16" r="1"/><rect x="3" y="10" width="18" height="12" rx="2"/><path d="M7 10V7a5 5 0 0 1 10 0v3"/>
22
+ </svg>
23
+ <% end %>
24
+ </a>
25
+ </li>
26
+ <% end %>
27
+ </ul>
28
+ </nav>
29
+ </div>
30
+
31
+ <div class="light-pane light-detail-pane overflow-y-auto">
32
+ <%= erb :_light_detail, locals: {light: selected_light} %>
33
+ </div>
34
+ </div>
35
+ </turbo-frame>
36
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <span class="light-detail-status flex items-center gap-2 mt-1 text-sm font-medium text-gray-500">
2
+ <span class="w-2.5 h-2.5 rounded-full bg-green-600"></span>
3
+ Green
4
+ </span>
5
+
6
+ <div class="light-detail-card mt-5 p-4 rounded-lg bg-green-50">
7
+ <p data-role="title" class="text-sm font-semibold text-green-800">Healthy</p>
8
+ <p data-role="comment" class="mt-1 text-xs text-green-800">Operating normally</p>
9
+ <p data-role="message" class="light-detail-message mt-3 pt-3 border-t border-green-100 text-sm text-green-900">No recent errors</p>
10
+ </div>
@@ -0,0 +1,10 @@
1
+ <span class="light-detail-status flex items-center gap-2 mt-1 text-sm font-medium text-gray-500">
2
+ <span class="w-2.5 h-2.5 rounded-full bg-green-600"></span>
3
+ Green (Locked)
4
+ </span>
5
+
6
+ <div class="light-detail-card mt-5 p-4 rounded-lg bg-green-50">
7
+ <p data-role="title" class="text-sm font-semibold text-green-800">Forced Healthy</p>
8
+ <p data-role="comment" class="mt-1 text-xs text-green-800">Override active - all requests processed</p>
9
+ <p data-role="message" class="light-detail-message mt-3 pt-3 border-t border-green-100 text-sm text-green-900">Light manually locked to green</p>
10
+ </div>
File without changes
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ class Admin
5
+ # A Sinatra dashboard listing every light of a configured system and its state.
6
+ #
7
+ # It reads its systems and its +read_only+ setting from +Stoplight::Admin+, so a host
8
+ # configures them there and mounts either app.
9
+ #
10
+ # @example Mounting in Rails
11
+ # Payments = Stoplight.register_system("Payments", data_store:)
12
+ #
13
+ # Stoplight::Admin.configure do |config|
14
+ # config.add_system Payments
15
+ # end
16
+ #
17
+ # mount Stoplight::Admin::Panel => "/stoplights"
18
+ #
19
+ class Panel < Sinatra::Base
20
+ helpers Helpers
21
+
22
+ set :systems, proc { Admin.settings.systems }
23
+ set :read_only, proc { Admin.settings.read_only? }
24
+ set :views, File.join(T.must(__dir__), "panel", "views")
25
+ set :nonce, proc { |request| }
26
+ set :public_folder, ASSETS_PATH
27
+ set :static_cache_control, [:public, max_age: ONE_YEAR_IN_SECONDS, immutable: true]
28
+
29
+ before do
30
+ if settings.read_only? && !request.get? && !request.head?
31
+ halt 403, "Stoplight Admin is running in read-only mode."
32
+ end
33
+ end
34
+
35
+ get "/" do
36
+ system = settings.systems.first
37
+
38
+ redirect system_url(system.config.id, "/lights")
39
+ end
40
+
41
+ get "/systems/:system_id/lights" do
42
+ lights = dependencies.light_list_action.call
43
+
44
+ erb :lights, layout: !turbo_frame_request?, locals: {lights: lights, selected_light: selected_light(lights)}
45
+ end
46
+
47
+ get "/systems/:system_id/lights/:light_id" do
48
+ lights = dependencies.light_list_action.call
49
+
50
+ erb :lights, layout: !turbo_frame_request?, locals: {lights: lights, selected_light: find_light(lights, params[:light_id])}
51
+ end
52
+ end
53
+ end
54
+ end
@@ -24,7 +24,7 @@
24
24
  <nav class="bg-white border-gray-200 dark:bg-gray-900">
25
25
  <div class="flex flex-wrap items-center justify-between p-4">
26
26
  <div class="flex items-center space-x-3 rtl:space-x-reverse">
27
- <a href="<%= url('/') %>" class="flex items-center space-x-3 rtl:space-x-reverse">
27
+ <a href="<%= url('/', false) %>" class="flex items-center space-x-3 rtl:space-x-reverse">
28
28
  🚦
29
29
  <span class="self-center text-2xl font-semibold whitespace-nowrap dark:text-white">Stoplight Admin</span>
30
30
  </a>
@@ -11,7 +11,7 @@ rescue LoadError
11
11
  raise <<~WARN
12
12
  "sinatra" and "sinatra-contrib" gems are unavailable and necessary for running Stoplight Admin panel
13
13
  Please add them to your Gemfile and run `bundle install`:
14
- gem "sinatra", required: false
14
+ gem "sinatra", require: false
15
15
  gem "sinatra-contrib", require: false
16
16
  WARN
17
17
  end
@@ -19,7 +19,8 @@ module Stoplight
19
19
  @scripts_path = scripts_path
20
20
  @redis = redis
21
21
  @shas = Hash.new do |hash, script_name|
22
- hash[script_name] = Digest::SHA1.hexdigest(resolve_source(script_name))
22
+ name = script_name #: String
23
+ hash[script_name] = Digest::SHA1.hexdigest(resolve_source(name))
23
24
  end
24
25
  @invoked = Set.new
25
26
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stoplight
4
- VERSION = Gem::Version.new("6.0.0")
4
+ VERSION = Gem::Version.new("6.0.1")
5
5
  end
@@ -0,0 +1,24 @@
1
+ module Stoplight
2
+ class Admin
3
+ class Panel
4
+ module Actions
5
+ class LightList
6
+ COLORS: Array[Domain::color]
7
+
8
+ @config_registry: ConfigRegistry
9
+ @storage: Wiring::System::Storage
10
+
11
+ def initialize: (
12
+ config_registry: ConfigRegistry,
13
+ storage: Wiring::System::Storage,
14
+ ) -> void
15
+
16
+ def call: -> Array[LightSummary]
17
+
18
+ private def build_light: (Domain::Config) -> LightSummary
19
+ private def sort_key: (LightSummary) -> Array[Comparable]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ module Stoplight
2
+ class Admin
3
+ class Panel
4
+ class Dependencies
5
+ @system: Wiring::System
6
+ @storage: Wiring::System::Storage
7
+
8
+ def initialize: (system: Wiring::System) -> void
9
+ def config_registry: -> ConfigRegistry
10
+ def light_list_action: -> Actions::LightList
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module Stoplight
2
+ class Admin
3
+ class Panel
4
+ module Helpers : Sinatra::Base
5
+ STATE_TEMPLATES: Hash[Array[Domain::color | Domain::state], Symbol]
6
+
7
+ def dependencies: -> Dependencies
8
+ def selected_light: (Array[LightSummary]) -> LightSummary?
9
+ def find_light: (Array[LightSummary], String) -> LightSummary
10
+ def state_template_for: (LightSummary) -> Symbol
11
+ def system_url: (String system_id, String path) -> String
12
+ def asset_path: (String) -> String
13
+ def find_system: (String) -> Wiring::System
14
+ def current_system_id: -> String
15
+ def current_system: -> Wiring::System
16
+ def turbo_frame_request?: -> bool
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ module Stoplight
2
+ class Admin
3
+ class Panel
4
+ class LightSummary < Data
5
+ attr_reader id: String
6
+ attr_reader name: String
7
+ attr_reader color: Domain::color
8
+ attr_reader lock_state: Domain::state
9
+
10
+ def self.new: (
11
+ id: String,
12
+ name: String,
13
+ color: Domain::color,
14
+ lock_state: Domain::state,
15
+ ) -> instance
16
+
17
+ def initialize: (
18
+ id: String,
19
+ name: String,
20
+ color: Domain::color,
21
+ lock_state: Domain::state,
22
+ ) -> void
23
+
24
+ def locked?: -> bool
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ module Stoplight
2
+ class Admin
3
+ class Panel < Sinatra::Base
4
+ include Helpers
5
+ end
6
+ end
7
+ end
@@ -7,6 +7,8 @@ module Stoplight
7
7
  include Helpers
8
8
 
9
9
  self.@systems: Array[Wiring::System]
10
+ def self.systems: -> Array[Wiring::System]
11
+ def self.read_only?: -> bool
10
12
  def self.add_system: (Wiring::System) -> void
11
13
  def self.__stoplight__reset_systems!: -> void
12
14
  def self.validate_persistent_system!: (Wiring::System) -> Wiring::System
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stoplight
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0
4
+ version: 6.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tëma Bolshakov
@@ -66,12 +66,27 @@ files:
66
66
  - lib/stoplight/admin/assets/flowbite.min.css
67
67
  - lib/stoplight/admin/assets/flowbite.min.js
68
68
  - lib/stoplight/admin/assets/icon.svg
69
+ - lib/stoplight/admin/assets/panel.css
69
70
  - lib/stoplight/admin/assets/turbo.es2017-esm.min.js
70
71
  - lib/stoplight/admin/config_registry.rb
71
72
  - lib/stoplight/admin/dependencies.rb
72
73
  - lib/stoplight/admin/helpers.rb
73
74
  - lib/stoplight/admin/light_view.rb
74
75
  - lib/stoplight/admin/lights_stats.rb
76
+ - lib/stoplight/admin/panel.rb
77
+ - lib/stoplight/admin/panel/actions/light_list.rb
78
+ - lib/stoplight/admin/panel/dependencies.rb
79
+ - lib/stoplight/admin/panel/helpers.rb
80
+ - lib/stoplight/admin/panel/light_summary.rb
81
+ - lib/stoplight/admin/panel/views/_empty.erb
82
+ - lib/stoplight/admin/panel/views/_light_detail.erb
83
+ - lib/stoplight/admin/panel/views/layout.erb
84
+ - lib/stoplight/admin/panel/views/lights.erb
85
+ - lib/stoplight/admin/panel/views/states/_green.erb
86
+ - lib/stoplight/admin/panel/views/states/_locked_green.erb
87
+ - lib/stoplight/admin/panel/views/states/_locked_red.erb
88
+ - lib/stoplight/admin/panel/views/states/_red.erb
89
+ - lib/stoplight/admin/panel/views/states/_yellow.erb
75
90
  - lib/stoplight/admin/views/_card.erb
76
91
  - lib/stoplight/admin/views/index.erb
77
92
  - lib/stoplight/admin/views/layout.erb
@@ -201,6 +216,11 @@ files:
201
216
  - sig/stoplight/admin/helpers.rbs
202
217
  - sig/stoplight/admin/light_view.rbs
203
218
  - sig/stoplight/admin/lights_stats.rbs
219
+ - sig/stoplight/admin/panel.rbs
220
+ - sig/stoplight/admin/panel/actions/light_list.rbs
221
+ - sig/stoplight/admin/panel/dependencies.rbs
222
+ - sig/stoplight/admin/panel/helpers.rbs
223
+ - sig/stoplight/admin/panel/light_summary.rbs
204
224
  - sig/stoplight/color.rbs
205
225
  - sig/stoplight/common/deprecations.rbs
206
226
  - sig/stoplight/data_store/base.rbs