ultra_settings 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|