ultra_settings 2.0.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +63 -0
- data/VERSION +1 -1
- data/app/application.css +9 -8
- data/app/application_vars.css.erb +31 -0
- data/app/configuration.html.erb +16 -9
- data/app/layout.css +5 -3
- data/app/layout.html.erb +1 -0
- data/app/layout_vars.css.erb +19 -0
- data/lib/ultra_settings/coerce.rb +22 -11
- data/lib/ultra_settings/configuration.rb +22 -19
- data/lib/ultra_settings/rack_app.rb +3 -2
- data/lib/ultra_settings/web_view.rb +18 -3
- data/lib/ultra_settings.rb +20 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a34c970ed06134a778e29f09ef7640a255a82f45bbf74e703963a7d9b911b598
|
4
|
+
data.tar.gz: 8065a6941af25b2d18b0e6617af074443c4de7da24541fad0d062f562a640c4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d740cea45e6d52bf0392f9c867661b24b55f01ed0b3bb557f9730876af973d08036a47197539cee655a584a11b07b3ecb7ffcbd51cf4a6032605c9ab59b9277b
|
7
|
+
data.tar.gz: f11544c978f8b17790d9fe50b5fb03338a680da9dd4e045cc6e45cad2ab5e6910b51c737fd2735052eb835232023707dbd93bb6460627376765c01779c1f099f
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## 2.2.0
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Added option for `UltraSettings.runtime_settings_url` to allow configuring a link for editing runtime settings from the web UI.
|
12
|
+
|
13
|
+
## 2.1.0
|
14
|
+
|
15
|
+
### Added
|
16
|
+
|
17
|
+
- Added option to specify the color scheme for the web UI when mounting the rack app to support dark mode.
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
|
21
|
+
- Times stored as strings representing the seconds since the epoch are now correctly parsed as Time objects.
|
22
|
+
|
7
23
|
## 2.0.0
|
8
24
|
|
9
25
|
### Fixed
|
data/README.md
CHANGED
@@ -10,6 +10,24 @@ UltraSettings is a Ruby gem designed for managing application settings from vari
|
|
10
10
|
|
11
11
|
UltraSettings emphasizes well-documented configuration. You can include documentation directly in the configuration code. The gem also includes a [web UI](#web-ui) that can be mounted as a Rack app or embedded in other views allowing admin users to easily view configuration settings and documentation.
|
12
12
|
|
13
|
+
## Table Of Contents
|
14
|
+
|
15
|
+
- [Key Features](#key-features)
|
16
|
+
- [Usage](#usage)
|
17
|
+
- [Defining Configurations](#defining-configurations)
|
18
|
+
- [Field Options](#field-options)
|
19
|
+
- [Environment Variables](#environment-variables)
|
20
|
+
- [Runtime Settings](#runtime-settings)
|
21
|
+
- [YAML Files](#yaml-files)
|
22
|
+
- [Removing The Hierarchy](#removing-the-hierarchy)
|
23
|
+
- [Accessing Settings](#accessing-settings)
|
24
|
+
- [Web UI](#web-ui)
|
25
|
+
- [Testing With UltraSettings](#testing-with-ultrasettings)
|
26
|
+
- [Rollout Percentages](#rollout-percentages)
|
27
|
+
- [Installation](#installation)
|
28
|
+
- [Contributing](#contributing)
|
29
|
+
- [License](#license)
|
30
|
+
|
13
31
|
## Key Features
|
14
32
|
|
15
33
|
This gem supports a three-layer hierarchy for defining configuration sources:
|
@@ -176,6 +194,8 @@ You can customize the behavior of runtime setting names with the following optio
|
|
176
194
|
|
177
195
|
- **Disabling Runtime Settings:** You can disable runtime settings as a default source for fields by setting `runtime_settings_disabled` to `true` in your configuration class. You can disable runtime settings on individual fields by setting `runtime_setting` on the field to `false`.
|
178
196
|
|
197
|
+
- **Editing Links** You can specify a URL for editing runtime settings from the web UI by setting `UltraSettings.runtime_settings_url` to the desired URL. This will add links to the runtime settings in the web UI. You can use the placeholder `${name}` in the URL which will be replaced with the name of the runtime setting. If you are using the `super_settings` gem for runtime settings, then you can target a setting by adding `#edit=${name}` to the root URL where `super_settings` is mounted.
|
198
|
+
|
179
199
|
If a setting value cannot be loaded from the runtime settings, then it's value will attempt to be loaded from a YAML file.
|
180
200
|
|
181
201
|
### YAML Files
|
@@ -346,6 +366,12 @@ mount Rack::Builder.new do
|
|
346
366
|
end, at: "/ultra_settings"
|
347
367
|
```
|
348
368
|
|
369
|
+
You can specify the color scheme by setting by providing the `color_scheme` option to the `UltraSettings::RackApp` class. The default color scheme is `:light`. You can also set the scheme to `:dark` or `:system`.
|
370
|
+
|
371
|
+
```ruby
|
372
|
+
UltraSettings::RackApp.new(color_scheme: :dark)
|
373
|
+
```
|
374
|
+
|
349
375
|
#### Embedding the Settings View in Admin Tools
|
350
376
|
|
351
377
|
If you prefer to embed the settings view directly into your own admin tools or dashboard, you can use the `UltraSettings::ApplicationView` class to render the settings interface within your existing views:
|
@@ -421,6 +447,25 @@ end
|
|
421
447
|
|
422
448
|
This approach keeps your tests clean and readable while allowing for flexible configuration management during testing.
|
423
449
|
|
450
|
+
### Rollout percentages
|
451
|
+
|
452
|
+
A common usage of configuration is to control rollout of new features by specifying a percentage value and then testing if a random number is less than it. If you implement this pattern in your configuration, then you should use something like the [consistent_random](https://github.com/bdurand/consistent_random) gem to ensure you are generating consistent values without your units of work.
|
453
|
+
|
454
|
+
```ruby
|
455
|
+
class MyServiceConfiguration < UltraSettings::Configuration
|
456
|
+
field :use_http2_percentage,
|
457
|
+
type: :float,
|
458
|
+
default: 0.0,
|
459
|
+
description: "Rollout percentage for using the new HTTP/2 driver"
|
460
|
+
|
461
|
+
# Using ConsistentRandom#rand instead of Kernel#rand to ensure that we
|
462
|
+
# get the same result within a request and don't oscillate back and forth
|
463
|
+
# every time we check if this is enabled.
|
464
|
+
def use_http2?
|
465
|
+
ConsistentRandom.new("MyServiceConfiguration.use_http2").rand < use_http2_percentage
|
466
|
+
end
|
467
|
+
end
|
468
|
+
```
|
424
469
|
|
425
470
|
## Installation
|
426
471
|
|
@@ -446,6 +491,24 @@ Open a pull request on [GitHub](https://github.com/bdurand/ultra_settings).
|
|
446
491
|
|
447
492
|
Please use the [standardrb](https://github.com/testdouble/standard) syntax and lint your code with `standardrb --fix` before submitting.
|
448
493
|
|
494
|
+
You can start a local rack server to test the web UI by running
|
495
|
+
|
496
|
+
```bash
|
497
|
+
bundle exec rackup
|
498
|
+
```
|
499
|
+
|
500
|
+
You can test with some setting set by setting environment variable used in the test configuration.
|
501
|
+
|
502
|
+
```bash
|
503
|
+
MY_SERVICE_HOST=host.example.com MY_SERVICE_TOKEN=secret bundle exec rackup
|
504
|
+
```
|
505
|
+
|
506
|
+
You can test dark mode by setting the `COLOR_SCHEME` environment variable.
|
507
|
+
|
508
|
+
```bash
|
509
|
+
COLOR_SCHEME=dark bundle exec rackup
|
510
|
+
```
|
511
|
+
|
449
512
|
## License
|
450
513
|
|
451
514
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.2.0
|
data/app/application.css
CHANGED
@@ -15,29 +15,30 @@
|
|
15
15
|
|
16
16
|
.ultra-settings-table thead th {
|
17
17
|
vertical-align: bottom;
|
18
|
-
border-bottom: 2px solid
|
18
|
+
border-bottom: 2px solid var(--table-border-color);
|
19
|
+
background-color: var(--table-header-bg-color);
|
19
20
|
}
|
20
21
|
|
21
22
|
.ultra-settings-table td, .ultra-settings-table th {
|
22
23
|
padding: 0.75rem;
|
23
24
|
vertical-align: top;
|
24
|
-
border-top: 1px solid
|
25
|
+
border-top: 1px solid var(--table-border-color);
|
25
26
|
}
|
26
27
|
|
27
28
|
.ultra-settings-table tbody tr:nth-of-type(odd) {
|
28
|
-
background-color:
|
29
|
+
background-color: var(--alt-row-color);
|
29
30
|
}
|
30
31
|
|
31
32
|
.ultra-settings-table code {
|
32
33
|
font-family: monospace;
|
33
34
|
font-size: 0.9rem;
|
34
35
|
display: inline;
|
35
|
-
color:
|
36
|
+
color: var(--code-color);
|
36
37
|
font-weight: 600;
|
37
38
|
}
|
38
39
|
|
39
40
|
.ultra-settings-table em {
|
40
|
-
color:
|
41
|
+
color: var(--em-color);
|
41
42
|
font-style: italic;
|
42
43
|
font-size: 0.9rem;
|
43
44
|
}
|
@@ -49,13 +50,13 @@
|
|
49
50
|
font-size: 1rem;
|
50
51
|
font-weight: 400;
|
51
52
|
line-height: 1.5;
|
52
|
-
color:
|
53
|
-
background-color:
|
53
|
+
color: var(--form-control-color);
|
54
|
+
background-color: var(--form-control-bg-color);
|
54
55
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
55
56
|
background-repeat: no-repeat;
|
56
57
|
background-position: right .75rem center;
|
57
58
|
background-size: 16px 12px;
|
58
|
-
border: 1px solid
|
59
|
+
border: 1px solid var(--form-control-border-color);
|
59
60
|
border-radius: .25rem;
|
60
61
|
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
61
62
|
-webkit-appearance: none;
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<% unless color_scheme == :dark %>
|
2
|
+
.ultra-settings-configuration {
|
3
|
+
--table-header-bg-color: #fff;
|
4
|
+
--table-border-color: #dee2e6;
|
5
|
+
--alt-row-color: rgba(0, 0, 0, .05);
|
6
|
+
--form-control-color: #495057;
|
7
|
+
--form-control-bg-color: #fff;
|
8
|
+
--form-control-border-color: #ced4da;
|
9
|
+
--code-color: darkred;
|
10
|
+
--em-color: gray;
|
11
|
+
}
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<% if color_scheme == :system %>
|
15
|
+
@media (prefers-color-scheme: dark) {
|
16
|
+
<% end %>
|
17
|
+
<% if color_scheme == :system || color_scheme == :dark %>
|
18
|
+
.ultra-settings-configuration {
|
19
|
+
--table-header-bg-color: #333;
|
20
|
+
--table-border-color: #555;
|
21
|
+
--alt-row-color: rgba(0, 0, 0, .30);
|
22
|
+
--form-control-color: #eee;
|
23
|
+
--form-control-bg-color: #666;
|
24
|
+
--form-control-border-color: #555;
|
25
|
+
--code-color: pink;
|
26
|
+
--em-color: #999;
|
27
|
+
}
|
28
|
+
<% end %>
|
29
|
+
<% if color_scheme == :system %>
|
30
|
+
}
|
31
|
+
<% end %>
|
data/app/configuration.html.erb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
<th>Notes</th>
|
21
21
|
</tr>
|
22
22
|
</thead>
|
23
|
-
<tbody>
|
23
|
+
<tbody translate="no">
|
24
24
|
<% configuration.class.fields.each do |field| %>
|
25
25
|
<% source = configuration.__source__(field.name) %>
|
26
26
|
<tr>
|
@@ -52,14 +52,14 @@
|
|
52
52
|
<% end %>
|
53
53
|
</td>
|
54
54
|
|
55
|
-
<td>
|
55
|
+
<td style="word-wrap: break-word;">
|
56
56
|
<% unless field.description.to_s.empty? %>
|
57
57
|
<div>
|
58
58
|
<%= html_escape(field.description) %>
|
59
59
|
</div>
|
60
60
|
<% end %>
|
61
61
|
|
62
|
-
<ul style="margin: 0; padding: 0;list-style-type: disc; list-style-position:
|
62
|
+
<ul style="margin: 0 0 0 1rem; padding: 0; list-style-type: disc; list-style-position: outside;">
|
63
63
|
<% if field.env_var && !configuration.class.environment_variables_disabled? %>
|
64
64
|
<li>
|
65
65
|
<% if source == :env %>
|
@@ -68,9 +68,8 @@
|
|
68
68
|
<% else %>
|
69
69
|
Can be
|
70
70
|
<% end %>
|
71
|
-
set with the
|
71
|
+
set with the environment variable
|
72
72
|
<code><%= show_defined_value(field.env_var, configuration.__value_from_source__(field.name, :env), field.secret?) %></code>
|
73
|
-
environment variable.
|
74
73
|
<% if source == :env %>
|
75
74
|
</strong>
|
76
75
|
<% end %>
|
@@ -84,12 +83,21 @@
|
|
84
83
|
<% else %>
|
85
84
|
Can be
|
86
85
|
<% end %>
|
87
|
-
set with the
|
86
|
+
set with the runtime setting
|
88
87
|
<code><%= show_defined_value(field.runtime_setting, configuration.__value_from_source__(field.name, :settings), field.secret?) %></code>
|
89
|
-
runtime setting.
|
90
88
|
<% if source == :settings %>
|
91
89
|
</strong>
|
92
90
|
<% end %>
|
91
|
+
|
92
|
+
<% edit_url = UltraSettings.runtime_settings_url(field.runtime_setting) %>
|
93
|
+
<% if edit_url %>
|
94
|
+
<a href="<%= html_escape(edit_url) %>" title="Edit <%= html_escape(field.runtime_setting) %>" style="text-decoration: none; color: inherit; vertical-align: middle;">
|
95
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-square" viewBox="0 0 16 16">
|
96
|
+
<path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
|
97
|
+
<path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5z"/>
|
98
|
+
</svg>
|
99
|
+
</a>
|
100
|
+
<% end %>
|
93
101
|
</li>
|
94
102
|
<% end %>
|
95
103
|
<% if field.yaml_key && !configuration.class.yaml_config_disabled? %>
|
@@ -100,9 +108,8 @@
|
|
100
108
|
<% else %>
|
101
109
|
Can be
|
102
110
|
<% end %>
|
103
|
-
set with the
|
111
|
+
set with the configuration file key
|
104
112
|
<code><%= show_defined_value(field.yaml_key, configuration.__value_from_source__(field.name, :yaml), field.secret?) %></code>
|
105
|
-
key in the configuration file.
|
106
113
|
<% if source == :yaml %>
|
107
114
|
</strong>
|
108
115
|
<% end %>
|
data/app/layout.css
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
* {
|
1
|
+
* {
|
2
|
+
box-sizing:border-box;
|
3
|
+
}
|
2
4
|
|
3
5
|
body {
|
4
6
|
font-family: sans-serif;
|
5
7
|
font-size: 1rem;
|
6
8
|
line-height: 1.5;
|
7
9
|
text-align: left;
|
8
|
-
color:
|
9
|
-
background-color:
|
10
|
+
color: var(--text-color);
|
11
|
+
background-color: var(--background-color);
|
10
12
|
margin: 0;
|
11
13
|
padding: 0;
|
12
14
|
}
|
data/app/layout.html.erb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
<title>Application Configuration</title>
|
6
6
|
<meta charset="utf-8">
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
8
|
+
<meta name="format-detection" content="telephone=no email=no date=no address=no">
|
8
9
|
<style type="text/css">
|
9
10
|
<%= @layout_css %>
|
10
11
|
<%= css %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<% unless color_scheme != :dark %>
|
2
|
+
:root {
|
3
|
+
--text-color: #212529;
|
4
|
+
--background-color: #ffffff;
|
5
|
+
}
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<% if color_scheme == :system %>
|
9
|
+
@media (prefers-color-scheme: dark) {
|
10
|
+
<% end %>
|
11
|
+
<% if color_scheme == :system || color_scheme == :dark %>
|
12
|
+
:root {
|
13
|
+
--text-color: #fff;
|
14
|
+
--background-color: #333;
|
15
|
+
}
|
16
|
+
<% end %>
|
17
|
+
<% if color_scheme == :system %>
|
18
|
+
}
|
19
|
+
<% end %>
|
@@ -18,6 +18,8 @@ module UltraSettings
|
|
18
18
|
]).freeze
|
19
19
|
# rubocop:enable Lint/BooleanSymbol
|
20
20
|
|
21
|
+
NUMERIC_REGEX = /\A-?\d+(?:\.\d+)?\z/
|
22
|
+
|
21
23
|
class << self
|
22
24
|
# Cast a value to a specific type.
|
23
25
|
#
|
@@ -33,13 +35,19 @@ module UltraSettings
|
|
33
35
|
when :float
|
34
36
|
value.is_a?(Float) ? value : value.to_s&.to_f
|
35
37
|
when :boolean
|
36
|
-
|
38
|
+
boolean(value)
|
37
39
|
when :datetime
|
38
|
-
|
40
|
+
time(value)
|
39
41
|
when :array
|
40
42
|
Array(value).map(&:to_s)
|
41
43
|
when :symbol
|
42
44
|
value.to_s.to_sym
|
45
|
+
when :rollout
|
46
|
+
if numeric?(value)
|
47
|
+
value.to_f
|
48
|
+
else
|
49
|
+
boolean(value)
|
50
|
+
end
|
43
51
|
else
|
44
52
|
value.to_s
|
45
53
|
end
|
@@ -50,13 +58,9 @@ module UltraSettings
|
|
50
58
|
# @param value [Object]
|
51
59
|
# @return [Boolean]
|
52
60
|
def boolean(value)
|
53
|
-
if value
|
54
|
-
|
55
|
-
|
56
|
-
nil
|
57
|
-
else
|
58
|
-
!FALSE_VALUES.include?(value)
|
59
|
-
end
|
61
|
+
return nil if blank?(value)
|
62
|
+
|
63
|
+
!FALSE_VALUES.include?(value)
|
60
64
|
end
|
61
65
|
|
62
66
|
# Cast a value to a Time object.
|
@@ -66,8 +70,9 @@ module UltraSettings
|
|
66
70
|
def time(value)
|
67
71
|
value = nil if value.nil? || value.to_s.empty?
|
68
72
|
return nil if value.nil?
|
69
|
-
|
70
|
-
|
73
|
+
|
74
|
+
time = if numeric?(value)
|
75
|
+
Time.at(value.to_f)
|
71
76
|
elsif value.respond_to?(:to_time)
|
72
77
|
value.to_time
|
73
78
|
else
|
@@ -79,9 +84,15 @@ module UltraSettings
|
|
79
84
|
time
|
80
85
|
end
|
81
86
|
|
87
|
+
# @return [Boolean] true if the value is a numeric type or a string representing a number.
|
88
|
+
def numeric?(value)
|
89
|
+
value.is_a?(Numeric) || (value.is_a?(String) && value.to_s.match?(NUMERIC_REGEX))
|
90
|
+
end
|
91
|
+
|
82
92
|
# @return [Boolean] true if the value is nil or empty.
|
83
93
|
def blank?(value)
|
84
94
|
return true if value.nil?
|
95
|
+
|
85
96
|
if value.respond_to?(:empty?)
|
86
97
|
value.empty?
|
87
98
|
else
|
@@ -7,6 +7,9 @@ module UltraSettings
|
|
7
7
|
ALLOWED_NAME_PATTERN = /\A[a-z_][a-zA-Z0-9_]*\z/
|
8
8
|
ALLOWED_TYPES = [:string, :symbol, :integer, :float, :boolean, :datetime, :array].freeze
|
9
9
|
|
10
|
+
@env_var_prefix = nil
|
11
|
+
@runtime_setting_prefix = nil
|
12
|
+
|
10
13
|
class << self
|
11
14
|
# Define a field on the configuration. This will create a getter method for the field.
|
12
15
|
# The field value will be read from the environment, runtime settings, or a YAML file
|
@@ -64,7 +67,7 @@ module UltraSettings
|
|
64
67
|
secret: secret
|
65
68
|
)
|
66
69
|
|
67
|
-
class_eval
|
70
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Security/Eval
|
68
71
|
def #{name}
|
69
72
|
__get_value__(#{name.inspect})
|
70
73
|
end
|
@@ -435,10 +438,10 @@ module UltraSettings
|
|
435
438
|
end
|
436
439
|
|
437
440
|
def initialize
|
438
|
-
@
|
439
|
-
@
|
440
|
-
@
|
441
|
-
@
|
441
|
+
@ultra_settings_mutex = Mutex.new
|
442
|
+
@ultra_settings_memoized_values = {}
|
443
|
+
@ultra_settings_override_values = {}
|
444
|
+
@ultra_settings_yaml_config = nil
|
442
445
|
end
|
443
446
|
|
444
447
|
def [](name)
|
@@ -450,7 +453,7 @@ module UltraSettings
|
|
450
453
|
end
|
451
454
|
|
452
455
|
def override!(values, &block)
|
453
|
-
save_val = @
|
456
|
+
save_val = @ultra_settings_override_values[Thread.current.object_id]
|
454
457
|
|
455
458
|
temp_values = (save_val || {}).dup
|
456
459
|
values.each do |key, value|
|
@@ -458,13 +461,13 @@ module UltraSettings
|
|
458
461
|
end
|
459
462
|
|
460
463
|
begin
|
461
|
-
@
|
462
|
-
@
|
464
|
+
@ultra_settings_mutex.synchronize do
|
465
|
+
@ultra_settings_override_values[Thread.current.object_id] = temp_values
|
463
466
|
end
|
464
467
|
yield
|
465
468
|
ensure
|
466
|
-
@
|
467
|
-
@
|
469
|
+
@ultra_settings_mutex.synchronize do
|
470
|
+
@ultra_settings_override_values[Thread.current.object_id] = save_val
|
468
471
|
end
|
469
472
|
end
|
470
473
|
end
|
@@ -530,12 +533,12 @@ module UltraSettings
|
|
530
533
|
field = self.class.send(:defined_fields)[name]
|
531
534
|
return nil unless field
|
532
535
|
|
533
|
-
if field.static? && @
|
534
|
-
return @
|
536
|
+
if field.static? && @ultra_settings_memoized_values.include?(name)
|
537
|
+
return @ultra_settings_memoized_values[name]
|
535
538
|
end
|
536
539
|
|
537
|
-
if @
|
538
|
-
value = field.coerce(@
|
540
|
+
if @ultra_settings_override_values[Thread.current.object_id]&.include?(name)
|
541
|
+
value = field.coerce(@ultra_settings_override_values[Thread.current.object_id][name])
|
539
542
|
else
|
540
543
|
env = ENV if field.env_var
|
541
544
|
settings = UltraSettings.__runtime_settings__ if field.runtime_setting
|
@@ -549,11 +552,11 @@ module UltraSettings
|
|
549
552
|
end
|
550
553
|
|
551
554
|
if field.static?
|
552
|
-
@
|
553
|
-
if @
|
554
|
-
value = @
|
555
|
+
@ultra_settings_mutex.synchronize do
|
556
|
+
if @ultra_settings_memoized_values.include?(name)
|
557
|
+
value = @ultra_settings_memoized_values[name]
|
555
558
|
else
|
556
|
-
@
|
559
|
+
@ultra_settings_memoized_values[name] = value
|
557
560
|
end
|
558
561
|
end
|
559
562
|
end
|
@@ -578,7 +581,7 @@ module UltraSettings
|
|
578
581
|
end
|
579
582
|
|
580
583
|
def __yaml_config__
|
581
|
-
@
|
584
|
+
@ultra_settings_yaml_config ||= self.class.load_yaml_config || {}
|
582
585
|
end
|
583
586
|
end
|
584
587
|
end
|
@@ -5,8 +5,9 @@ module UltraSettings
|
|
5
5
|
# No setting values are displayed, but you should still add some
|
6
6
|
# sort of authentication if you want to use this in production.
|
7
7
|
class RackApp
|
8
|
-
def initialize
|
8
|
+
def initialize(color_scheme: nil)
|
9
9
|
@webview = nil
|
10
|
+
@color_scheme = color_scheme
|
10
11
|
end
|
11
12
|
|
12
13
|
def call(env)
|
@@ -19,7 +20,7 @@ module UltraSettings
|
|
19
20
|
if ENV.fetch("RAILS_ENV", ENV.fetch("RACK_ENV", "development")) == "development"
|
20
21
|
@webview = nil
|
21
22
|
end
|
22
|
-
@webview ||= WebView.new
|
23
|
+
@webview ||= WebView.new(color_scheme: @color_scheme)
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
@@ -5,10 +5,13 @@ module UltraSettings
|
|
5
5
|
class WebView
|
6
6
|
attr_reader :css
|
7
7
|
|
8
|
-
|
8
|
+
# @param color_scheme [Symbol] The color scheme to use in the UI. This can be `:light`,
|
9
|
+
# `:dark`, or `:system`. The default is `:light`.
|
10
|
+
def initialize(color_scheme: :light)
|
11
|
+
color_scheme = (color_scheme || :light).to_sym
|
9
12
|
@layout_template = erb_template("layout.html.erb")
|
10
|
-
@layout_css =
|
11
|
-
@css =
|
13
|
+
@layout_css = layout_css(color_scheme)
|
14
|
+
@css = application_css(color_scheme)
|
12
15
|
end
|
13
16
|
|
14
17
|
def render_settings
|
@@ -32,5 +35,17 @@ module UltraSettings
|
|
32
35
|
def app_dir
|
33
36
|
File.expand_path(File.join("..", "..", "app"), __dir__)
|
34
37
|
end
|
38
|
+
|
39
|
+
def layout_css(color_scheme)
|
40
|
+
vars = erb_template("layout_vars.css.erb").result(binding)
|
41
|
+
css = read_app_file("layout.css")
|
42
|
+
"#{vars}\n#{css}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def application_css(color_scheme)
|
46
|
+
vars = erb_template("application_vars.css.erb").result(binding)
|
47
|
+
css = read_app_file("application.css")
|
48
|
+
"#{vars}\n#{css}"
|
49
|
+
end
|
35
50
|
end
|
36
51
|
end
|
data/lib/ultra_settings.rb
CHANGED
@@ -6,6 +6,7 @@ require "time"
|
|
6
6
|
require "pathname"
|
7
7
|
require "singleton"
|
8
8
|
require "digest"
|
9
|
+
require "uri"
|
9
10
|
|
10
11
|
require_relative "ultra_settings/configuration"
|
11
12
|
require_relative "ultra_settings/coerce"
|
@@ -33,6 +34,7 @@ module UltraSettings
|
|
33
34
|
@configurations = {}
|
34
35
|
@mutex = Mutex.new
|
35
36
|
@runtime_settings = nil
|
37
|
+
@runtime_settings_url = nil
|
36
38
|
|
37
39
|
class << self
|
38
40
|
# Adds a configuration to the root namespace. The configuration will be
|
@@ -167,6 +169,24 @@ module UltraSettings
|
|
167
169
|
@runtime_settings
|
168
170
|
end
|
169
171
|
|
172
|
+
# Set the URL for changing runtime settings. If this is set, then a link to the
|
173
|
+
# URL will be displayed in the web view for fields that support runtime settings.
|
174
|
+
# The URL may contain a `${name}` placeholder that will be replaced with the name
|
175
|
+
# of the setting.
|
176
|
+
attr_writer :runtime_settings_url
|
177
|
+
|
178
|
+
# Get the URL for changing runtime settings.
|
179
|
+
#
|
180
|
+
# @param name [String] The name of the setting.
|
181
|
+
# @return [String, nil]
|
182
|
+
# @api private
|
183
|
+
def runtime_settings_url(name)
|
184
|
+
url = @runtime_settings_url.to_s
|
185
|
+
return nil if url.empty?
|
186
|
+
|
187
|
+
url.gsub("${name}", URI.encode_www_form_component(name))
|
188
|
+
end
|
189
|
+
|
170
190
|
def fields_secret_by_default=(value)
|
171
191
|
Configuration.fields_secret_by_default = value
|
172
192
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ultra_settings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -37,10 +37,12 @@ files:
|
|
37
37
|
- VERSION
|
38
38
|
- app/application.css
|
39
39
|
- app/application.js
|
40
|
+
- app/application_vars.css.erb
|
40
41
|
- app/configuration.html.erb
|
41
42
|
- app/index.html.erb
|
42
43
|
- app/layout.css
|
43
44
|
- app/layout.html.erb
|
45
|
+
- app/layout_vars.css.erb
|
44
46
|
- lib/ultra_settings.rb
|
45
47
|
- lib/ultra_settings/application_view.rb
|
46
48
|
- lib/ultra_settings/coerce.rb
|