ultra_settings 2.6.0 → 2.7.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 +14 -1
- data/README.md +5 -3
- data/VERSION +1 -1
- data/app/application.css +67 -29
- data/app/application_vars.css.erb +11 -5
- data/app/configuration.html.erb +36 -23
- data/app/index.html.erb +0 -14
- data/lib/ultra_settings/application_view.rb +14 -0
- data/lib/ultra_settings/coerce.rb +3 -0
- data/lib/ultra_settings/config_helper.rb +12 -8
- data/lib/ultra_settings/configuration.rb +1 -1
- data/lib/ultra_settings/configuration_view.rb +94 -5
- data/lib/ultra_settings/field.rb +1 -0
- data/lib/ultra_settings/rack_app.rb +7 -0
- data/lib/ultra_settings/uninitialized_runtime_settings.rb +12 -7
- data/lib/ultra_settings/view_helper.rb +11 -0
- data/lib/ultra_settings/web_view.rb +9 -1
- data/lib/ultra_settings/yaml_config.rb +7 -0
- data/lib/ultra_settings.rb +35 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f70521135220d74fe5ef4fbc6261c9d5b8a93f200f898af0fead2ebb7d31cbfd
|
4
|
+
data.tar.gz: 42330a1a294bee7ab53c61f37b56cd0b5b6f309326f1809bfd012cbfcd67fa58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aab2c06121a67e227f1628d1dd3a22590e0bb174f132506840112278a5c09484e57dd6bc176ddbb35d576388c29bb5f6da462473f1c5ebf76724fe8677312ed2
|
7
|
+
data.tar.gz: f7e9bd08a2958def30780e0ef966d8b90321d3f9c1bf469677b7c51ab8b512e867bf0e1fc1d910d72f24c9f71818a34050b3a2dbfdc2c5adb9afa4a3e048948a
|
data/CHANGELOG.md
CHANGED
@@ -4,11 +4,24 @@ 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.7.0
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Added new setting to indicate if the runtime settings engine is secure. If the engine is marked as not secure, then runtime settings will be disabled for all fields marked as secret. This protects sensitive information from being exposed in the web UI or through the API. The default value is `true` to maintain backwards compatibility.
|
12
|
+
|
13
|
+
## 2.6.1
|
14
|
+
|
15
|
+
### Added
|
16
|
+
|
17
|
+
- Show icons on the web UI that open a dialog with the current value for each data source.
|
18
|
+
- Added support for passing the field description in `UltraSettings.runtime_settings_url` using the `${description}` placeholder in the URL.
|
19
|
+
|
7
20
|
## 2.6.0
|
8
21
|
|
9
22
|
### Added
|
10
23
|
|
11
|
-
- Added support for passing the type in `UltraSettings.runtime_settings_url`
|
24
|
+
- Added support for passing the type in `UltraSettings.runtime_settings_url` using the `${type}` placeholder in the URL.
|
12
25
|
|
13
26
|
### Changed
|
14
27
|
|
data/README.md
CHANGED
@@ -81,7 +81,6 @@ class MyServiceConfiguration < UltraSettings::Configuration
|
|
81
81
|
field :auth_token,
|
82
82
|
type: :string,
|
83
83
|
env_var: "MY_SERVICE_TOKEN",
|
84
|
-
runtime_setting: false,
|
85
84
|
yaml_key: false,
|
86
85
|
description: "Bearer token for accessing the service",
|
87
86
|
secret: true
|
@@ -114,7 +113,7 @@ You can customize the behavior of each field using various options:
|
|
114
113
|
|
115
114
|
- `:default_if` - Provides a condition for when the default should be used. This should be a Proc or the name of a method within the class. Useful for ensuring values meet specific constraints. This can provide protection from misconfiguration that can break the application. In the above example, the default value for `timeout` will be used if the value is less than or equal to 0.
|
116
115
|
|
117
|
-
- `:secret` - Marks the field as secret. Secret fields are not displayed in the web UI. By default, all fields are considered secret to avoid accidentally exposing sensitive values. You can change this default behavior by setting `fields_secret_by_default` to `false` either globally or per configuration.
|
116
|
+
- `:secret` - Marks the field as secret. Secret fields are not displayed in the web UI. By default, all fields are considered secret to avoid accidentally exposing sensitive values. You can change this default behavior by setting `fields_secret_by_default` to `false` either globally or per configuration. Additionaly, if you set `UltraSettings.runtime_settings_secure` to false, then runtime settings will be disabled on secret fields.
|
118
117
|
|
119
118
|
- `:env_var` - Overrides the environment variable name used to populate the field. This is useful if the variable name does not follow the conventional pattern. Set this to `false` to disable loading the field from an environment variable.
|
120
119
|
|
@@ -172,6 +171,9 @@ UltraSettings.runtime_settings = RedisRuntimeSettings.new
|
|
172
171
|
|
173
172
|
The runtime settings implementation may also define an `array` method that takes a single parameter to return an array value. If this method is not implemented, then array values must be returned as single line CSV strings.
|
174
173
|
|
174
|
+
> [!TIP]
|
175
|
+
> If your runtime settings implementation does not securely store values, you should set `UltraSettings.runtime_settings_secure` to `false`. This will disable runtime settings on fields marked as secret to prevent leaking sensitive information.
|
176
|
+
|
175
177
|
#### Using the `super_settings` gem
|
176
178
|
|
177
179
|
There is a companion gem [super_settings](https://github.com/bdurand/super_settings) that can be used as a drop in implementation for the runtime settings. You just need to set the runtime settings to the `SuperSettings` object.
|
@@ -211,7 +213,7 @@ You can customize the behavior of runtime setting names with the following optio
|
|
211
213
|
|
212
214
|
- **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`.
|
213
215
|
|
214
|
-
- **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 placeholders `${name}
|
216
|
+
- **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 placeholders `${name}`, `${type}`, and `${description}` in the URL which will be replaced with the name, type, and description of the field respectively. If you are using the `super_settings` gem for runtime settings, then you can target a setting by adding `#edit=${name}&type=${type}&description=${description}` to the root URL where `super_settings` is mounted.
|
215
217
|
|
216
218
|
If a setting value cannot be loaded from the runtime settings, then it's value will attempt to be loaded from a YAML file.
|
217
219
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.7.0
|
data/app/application.css
CHANGED
@@ -6,7 +6,6 @@
|
|
6
6
|
margin: 0;
|
7
7
|
}
|
8
8
|
|
9
|
-
/* Configuration file header */
|
10
9
|
.ultra-settings-config-file {
|
11
10
|
margin-bottom: 1.5rem;
|
12
11
|
padding: 1rem;
|
@@ -23,7 +22,7 @@
|
|
23
22
|
|
24
23
|
.ultra-settings-config-file-path {
|
25
24
|
font-family: monospace;
|
26
|
-
font-size: 0.
|
25
|
+
font-size: 0.875rem;
|
27
26
|
color: var(--code-color);
|
28
27
|
font-weight: 600;
|
29
28
|
}
|
@@ -34,14 +33,16 @@
|
|
34
33
|
margin-left: 0.5rem;
|
35
34
|
}
|
36
35
|
|
37
|
-
/* Fields container */
|
38
36
|
.ultra-settings-fields {
|
39
37
|
display: flex;
|
40
38
|
flex-direction: column;
|
41
|
-
gap:
|
39
|
+
gap: 1.75rem;
|
40
|
+
}
|
41
|
+
|
42
|
+
.ultra-settings-fields svg {
|
43
|
+
vertical-align: middle;
|
42
44
|
}
|
43
45
|
|
44
|
-
/* Individual field card */
|
45
46
|
.ultra-settings-field {
|
46
47
|
border: 1px solid var(--field-border-color);
|
47
48
|
border-radius: 0.5rem;
|
@@ -49,7 +50,6 @@
|
|
49
50
|
overflow: hidden;
|
50
51
|
}
|
51
52
|
|
52
|
-
/* Field header */
|
53
53
|
.ultra-settings-field-header {
|
54
54
|
display: flex;
|
55
55
|
justify-content: space-between;
|
@@ -80,7 +80,6 @@
|
|
80
80
|
letter-spacing: 0.025em;
|
81
81
|
}
|
82
82
|
|
83
|
-
/* Field badges */
|
84
83
|
.ultra-settings-field-badge {
|
85
84
|
display: inline-block;
|
86
85
|
padding: 0.125rem 0.5rem;
|
@@ -101,16 +100,15 @@
|
|
101
100
|
color: var(--static-badge-text-color);
|
102
101
|
}
|
103
102
|
|
104
|
-
/* Field value */
|
105
103
|
.ultra-settings-field-value {
|
106
104
|
padding: 1rem;
|
107
105
|
background-color: var(--value-bg-color);
|
108
106
|
border-bottom: 1px solid var(--field-border-color);
|
109
107
|
}
|
110
108
|
|
111
|
-
.ultra-settings-field-value
|
109
|
+
code.ultra-settings-field-data-value {
|
112
110
|
font-family: monospace;
|
113
|
-
font-size: 0.
|
111
|
+
font-size: 0.875rem;
|
114
112
|
word-break: break-all;
|
115
113
|
color: var(--value-text-color);
|
116
114
|
background-color: var(--value-code-bg-color);
|
@@ -122,14 +120,11 @@
|
|
122
120
|
.ultra-settings-nil-value {
|
123
121
|
font-style: italic;
|
124
122
|
color: var(--nil-color);
|
125
|
-
font-size: 0.9rem;
|
126
123
|
}
|
127
124
|
|
128
|
-
/* Field description */
|
129
125
|
.ultra-settings-field-description {
|
130
126
|
padding: 0.75rem 1rem;
|
131
127
|
color: var(--description-color);
|
132
|
-
font-size: 0.9rem;
|
133
128
|
line-height: 1.5;
|
134
129
|
border-bottom: 1px solid var(--field-border-color);
|
135
130
|
display: flex;
|
@@ -141,15 +136,6 @@
|
|
141
136
|
flex: 1;
|
142
137
|
}
|
143
138
|
|
144
|
-
.ultra-settings-info-icon {
|
145
|
-
width: 16px;
|
146
|
-
height: 16px;
|
147
|
-
flex-shrink: 0;
|
148
|
-
margin-top: 0.125rem; /* Align with first line of text based on line-height */
|
149
|
-
color: var(--description-color);
|
150
|
-
}
|
151
|
-
|
152
|
-
/* Sources section */
|
153
139
|
.ultra-settings-field-sources {
|
154
140
|
padding: 0.5rem;
|
155
141
|
}
|
@@ -172,7 +158,7 @@
|
|
172
158
|
}
|
173
159
|
|
174
160
|
.ultra-settings-source-type {
|
175
|
-
font-size: 0.
|
161
|
+
font-size: 0.875rem;
|
176
162
|
font-weight: 500;
|
177
163
|
color: var(--source-type-color);
|
178
164
|
text-transform: uppercase;
|
@@ -182,8 +168,9 @@
|
|
182
168
|
|
183
169
|
.ultra-settings-source-value {
|
184
170
|
font-family: monospace;
|
185
|
-
font-size: 0.
|
171
|
+
font-size: 0.875rem;
|
186
172
|
color: var(--source-value-color);
|
173
|
+
font-weight: 550;
|
187
174
|
flex: 1;
|
188
175
|
margin: 0 0.75rem;
|
189
176
|
word-break: break-all;
|
@@ -197,6 +184,26 @@
|
|
197
184
|
letter-spacing: 0.025em;
|
198
185
|
}
|
199
186
|
|
187
|
+
.ultra-settings-source-value-dfn {
|
188
|
+
display: inline-block;
|
189
|
+
margin-left: 0.25rem;
|
190
|
+
}
|
191
|
+
|
192
|
+
.ultra-settings-icon-info {
|
193
|
+
color: var(--info-color);
|
194
|
+
cursor: pointer;
|
195
|
+
}
|
196
|
+
|
197
|
+
.ultra-settings-icon-not-set {
|
198
|
+
color: var(--warning-color);
|
199
|
+
cursor: pointer;
|
200
|
+
}
|
201
|
+
|
202
|
+
.ultra-settings-icon-secret {
|
203
|
+
color: var(--disabled-color);
|
204
|
+
cursor: pointer;
|
205
|
+
}
|
206
|
+
|
200
207
|
.ultra-settings-edit-link {
|
201
208
|
color: var(--edit-link-color);
|
202
209
|
text-decoration: none;
|
@@ -211,11 +218,6 @@
|
|
211
218
|
opacity: 1;
|
212
219
|
}
|
213
220
|
|
214
|
-
.ultra-settings-edit-icon {
|
215
|
-
width: 16px;
|
216
|
-
height: 16px;
|
217
|
-
}
|
218
|
-
|
219
221
|
.ultra-settings-select {
|
220
222
|
display: inline-block;
|
221
223
|
padding: .375rem 2.25rem .375rem .75rem;
|
@@ -236,3 +238,39 @@
|
|
236
238
|
-moz-appearance: none;
|
237
239
|
appearance: none;
|
238
240
|
}
|
241
|
+
|
242
|
+
.ultra-settings-dialog {
|
243
|
+
min-width: 20rem;
|
244
|
+
padding: 0;
|
245
|
+
border: 1px solid var(--field-border-color);
|
246
|
+
border-radius: 0.375rem;
|
247
|
+
}
|
248
|
+
|
249
|
+
.ultra-settings-dialog-header {
|
250
|
+
padding: 0.5rem;
|
251
|
+
background-color: var(--field-header-bg-color);
|
252
|
+
color: var(--field-header-text-color);
|
253
|
+
font-size: 1rem;
|
254
|
+
display: flex;
|
255
|
+
align-items: top;
|
256
|
+
}
|
257
|
+
|
258
|
+
.ultra-settings-dialog-title {
|
259
|
+
flex: 1;
|
260
|
+
text-align: center;
|
261
|
+
font-weight: 550;
|
262
|
+
}
|
263
|
+
|
264
|
+
.ultra-settings-dialog-close {
|
265
|
+
border: none;
|
266
|
+
background: none;
|
267
|
+
color: var(--field-header-text-color);
|
268
|
+
cursor: pointer;
|
269
|
+
padding: 0.25rem;
|
270
|
+
}
|
271
|
+
|
272
|
+
.ultra-settings-dialog-body {
|
273
|
+
padding: 1rem;
|
274
|
+
background-color: var(--background-color);
|
275
|
+
color: var(--text-color);
|
276
|
+
}
|
@@ -10,7 +10,8 @@
|
|
10
10
|
--config-file-border-color: #e8e8e8;
|
11
11
|
--field-bg-color: #ffffff;
|
12
12
|
--field-border-color: #b8b8b8;
|
13
|
-
--field-header-bg-color: #
|
13
|
+
--field-header-bg-color: #e8e8e8;
|
14
|
+
--field-header-text-color: #212529;
|
14
15
|
--value-bg-color: #fdfdfe;
|
15
16
|
--value-text-color: #212529;
|
16
17
|
--value-code-bg-color: #f8f8f8;
|
@@ -18,7 +19,9 @@
|
|
18
19
|
--type-color: #6c757d;
|
19
20
|
--description-color: #4a83b5;
|
20
21
|
--nil-color: #6c757d;
|
21
|
-
--warning-color: #
|
22
|
+
--warning-color: #b9202f;
|
23
|
+
--info-color: #6ea8fe;
|
24
|
+
--disabled-color: #adb5bd;
|
22
25
|
|
23
26
|
/* Source colors */
|
24
27
|
--source-bg-color: #f8f9fa;
|
@@ -26,7 +29,7 @@
|
|
26
29
|
--source-active-bg-color: #e7f3ff;
|
27
30
|
--source-active-border-color: #0d6efd;
|
28
31
|
--source-type-color: #666666;
|
29
|
-
--source-value-color: #
|
32
|
+
--source-value-color: #444444;
|
30
33
|
--source-indicator-color: #0d6efd;
|
31
34
|
|
32
35
|
/* Badge colors */
|
@@ -48,15 +51,16 @@
|
|
48
51
|
--form-control-color: #eee;
|
49
52
|
--form-control-bg-color: #666;
|
50
53
|
--form-control-border-color: #555;
|
51
|
-
--code-color: #
|
54
|
+
--code-color: #fd76a3;
|
52
55
|
--em-color: #adb5bd;
|
53
56
|
|
54
57
|
/* Card layout colors */
|
55
|
-
--config-file-bg-color: #
|
58
|
+
--config-file-bg-color: #4b4b4b;
|
56
59
|
--config-file-border-color: #444;
|
57
60
|
--field-bg-color: #1e1e1e;
|
58
61
|
--field-border-color: #444;
|
59
62
|
--field-header-bg-color: #2b2b2b;
|
63
|
+
--field-header-text-color: #ced4da;
|
60
64
|
--value-bg-color: #252525;
|
61
65
|
--value-text-color: #e9ecef;
|
62
66
|
--value-code-bg-color: #2b2b2b;
|
@@ -65,6 +69,8 @@
|
|
65
69
|
--description-color: #a9d9f8;
|
66
70
|
--nil-color: #cdcecfff;
|
67
71
|
--warning-color: #dc3545;
|
72
|
+
--info-color: #6ea8fe;
|
73
|
+
--disabled-color: #adb5bd;
|
68
74
|
|
69
75
|
/* Source colors */
|
70
76
|
--source-bg-color: #2b2b2b;
|
data/app/configuration.html.erb
CHANGED
@@ -32,17 +32,15 @@
|
|
32
32
|
<% if configuration[field.name].nil? %>
|
33
33
|
<span class="ultra-settings-nil-value">nil</span>
|
34
34
|
<% elsif field.secret? %>
|
35
|
-
<code><%= html_escape(secret_value(configuration[field.name])) %></code>
|
35
|
+
<code class="ultra-settings-field-data-value"><%= html_escape(secret_value(configuration[field.name])) %></code>
|
36
36
|
<% else %>
|
37
|
-
<code><%= html_escape(display_value(configuration[field.name])) %></code>
|
37
|
+
<code class="ultra-settings-field-data-value"><%= html_escape(display_value(configuration[field.name])) %></code>
|
38
38
|
<% end %>
|
39
39
|
</div>
|
40
40
|
|
41
41
|
<% unless field.description.to_s.empty? %>
|
42
42
|
<div class="ultra-settings-field-description">
|
43
|
-
|
44
|
-
<use href="#info-icon"/>
|
45
|
-
</svg>
|
43
|
+
<%= info_icon %>
|
46
44
|
<div class="ultra-settings-description-text">
|
47
45
|
<%= html_escape(field.description) %>
|
48
46
|
</div>
|
@@ -52,8 +50,13 @@
|
|
52
50
|
<div class="ultra-settings-field-sources">
|
53
51
|
<% if field.env_var && !configuration.class.environment_variables_disabled? %>
|
54
52
|
<div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :env %>">
|
55
|
-
<span class="ultra-settings-source-type">
|
56
|
-
|
53
|
+
<span class="ultra-settings-source-type">
|
54
|
+
Environment Variable
|
55
|
+
</span>
|
56
|
+
<code class="ultra-settings-source-value">
|
57
|
+
<%= field.env_var %>
|
58
|
+
<%= show_defined_value(field.env_var, configuration.__value_from_source__(field.name, :env), field.secret?) %>
|
59
|
+
</code>
|
57
60
|
<% if source == :env %>
|
58
61
|
<span class="ultra-settings-source-indicator">Currently active</span>
|
59
62
|
<% end %>
|
@@ -63,16 +66,17 @@
|
|
63
66
|
<% if field.runtime_setting && !configuration.class.runtime_settings_disabled? %>
|
64
67
|
<div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :settings %>">
|
65
68
|
<span class="ultra-settings-source-type">Runtime Setting</span>
|
66
|
-
<code class="ultra-settings-source-value"
|
69
|
+
<code class="ultra-settings-source-value">
|
70
|
+
<%= field.runtime_setting %>
|
71
|
+
<%= show_defined_value(field.runtime_setting, configuration.__value_from_source__(field.name, :settings), field.secret?) %>
|
72
|
+
</code>
|
67
73
|
<% if source == :settings %>
|
68
74
|
<span class="ultra-settings-source-indicator">Currently active</span>
|
69
75
|
<% end %>
|
70
|
-
<% edit_url = UltraSettings.runtime_settings_url(field.runtime_setting, field.type) %>
|
76
|
+
<% edit_url = UltraSettings.runtime_settings_url(name: field.runtime_setting, type: field.type, description: field.description) %>
|
71
77
|
<% if edit_url %>
|
72
78
|
<a href="<%= html_escape(edit_url) %>" class="ultra-settings-edit-link" title="Edit <%= html_escape(field.runtime_setting) %>">
|
73
|
-
|
74
|
-
<use href="#edit-icon"/>
|
75
|
-
</svg>
|
79
|
+
<%= edit_icon %>
|
76
80
|
</a>
|
77
81
|
<% end %>
|
78
82
|
</div>
|
@@ -81,25 +85,22 @@
|
|
81
85
|
<% if field.yaml_key && !configuration.class.yaml_config_disabled? %>
|
82
86
|
<div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :yaml %>">
|
83
87
|
<span class="ultra-settings-source-type">Configuration File</span>
|
84
|
-
<code class="ultra-settings-source-value"
|
88
|
+
<code class="ultra-settings-source-value">
|
89
|
+
<%= field.yaml_key %>
|
90
|
+
<%= show_defined_value(field.yaml_key, configuration.__value_from_source__(field.name, :yaml), field.secret?) %>
|
91
|
+
</code>
|
85
92
|
<% if source == :yaml %>
|
86
93
|
<span class="ultra-settings-source-indicator">Currently active</span>
|
87
94
|
<% end %>
|
88
95
|
</div>
|
89
96
|
<% end %>
|
90
97
|
|
91
|
-
<% if field.default.nil? %>
|
92
|
-
<% if source == :default %>
|
93
|
-
<div class="ultra-settings-source ultra-settings-source-active">
|
94
|
-
<span class="ultra-settings-source-type">Default Value</span>
|
95
|
-
<span class="ultra-settings-source-value"><em>Not set</em></span>
|
96
|
-
<span class="ultra-settings-source-indicator">Currently active</span>
|
97
|
-
</div>
|
98
|
-
<% end %>
|
99
|
-
<% else %>
|
98
|
+
<% if !field.default.nil? || source == :default %>
|
100
99
|
<div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :default %>">
|
101
100
|
<span class="ultra-settings-source-type">Default Value</span>
|
102
|
-
<code class="ultra-settings-source-value"
|
101
|
+
<code class="ultra-settings-source-value">
|
102
|
+
<%= show_defined_value("Default Value", field.default, field.secret?) %>
|
103
|
+
</code>
|
103
104
|
<% if source == :default %>
|
104
105
|
<span class="ultra-settings-source-indicator">Currently active</span>
|
105
106
|
<% end %>
|
@@ -109,4 +110,16 @@
|
|
109
110
|
</div>
|
110
111
|
<% end %>
|
111
112
|
</div>
|
113
|
+
|
114
|
+
<dialog class="ultra-settings-dialog" closedby="any">
|
115
|
+
<div class="ultra-settings-dialog-header">
|
116
|
+
<div class="ultra-settings-dialog-title"></div>
|
117
|
+
<button class="ultra-settings-dialog-close" onclick="this.closest('.ultra-settings-dialog').close();">
|
118
|
+
<%= close_icon %>
|
119
|
+
</button>
|
120
|
+
</div>
|
121
|
+
<div class="ultra-settings-dialog-body">
|
122
|
+
<code class="ultra-settings-field-data-value ultra-settings-dialog-value"></code>
|
123
|
+
</div>
|
124
|
+
</dialog>
|
112
125
|
</div>
|
data/app/index.html.erb
CHANGED
@@ -1,19 +1,5 @@
|
|
1
1
|
<%= style_tag %>
|
2
2
|
|
3
|
-
<!-- SVG Icons -->
|
4
|
-
<svg style="display: none;" xmlns="http://www.w3.org/2000/svg">
|
5
|
-
<defs>
|
6
|
-
<symbol id="edit-icon" viewBox="0 0 16 16">
|
7
|
-
<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"/>
|
8
|
-
<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"/>
|
9
|
-
</symbol>
|
10
|
-
<symbol id="info-icon" viewBox="0 0 16 16">
|
11
|
-
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
|
12
|
-
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
|
13
|
-
</symbol>
|
14
|
-
</defs>
|
15
|
-
</svg>
|
16
|
-
|
17
3
|
<div class="ultra-settings">
|
18
4
|
<div class="ultra-settings-nav">
|
19
5
|
<form onsubmit="return false" style="margin-bottom: 0.5rem;">
|
@@ -15,23 +15,37 @@ module UltraSettings
|
|
15
15
|
class ApplicationView
|
16
16
|
attr_reader :css
|
17
17
|
|
18
|
+
# Initialize the application view with a color scheme.
|
19
|
+
#
|
20
|
+
# @param color_scheme [Symbol] The color scheme to use (:light, :dark, or :system).
|
18
21
|
def initialize(color_scheme: :light)
|
19
22
|
@css = application_css(color_scheme)
|
20
23
|
@css = @css.html_safe if @css.respond_to?(:html_safe)
|
21
24
|
end
|
22
25
|
|
26
|
+
# Render the HTML for the configuration settings UI.
|
27
|
+
#
|
28
|
+
# @param select_class [String] CSS class for the select element.
|
29
|
+
# @param table_class [String] CSS class for the table element (for backwards compatibility).
|
30
|
+
# @return [String] The rendered HTML.
|
23
31
|
def render(select_class: "ultra-settings-select", table_class: "")
|
24
32
|
html = ViewHelper.erb_template("index.html.erb").result(binding)
|
25
33
|
html = html.html_safe if html.respond_to?(:html_safe)
|
26
34
|
html
|
27
35
|
end
|
28
36
|
|
37
|
+
# Generate an HTML style tag with the CSS for the view.
|
38
|
+
#
|
39
|
+
# @return [String] The HTML style tag with CSS.
|
29
40
|
def style_tag
|
30
41
|
tag = "<style type=\"text/css\">\n#{css}\n</style>"
|
31
42
|
tag = tag.html_safe if tag.respond_to?(:html_safe)
|
32
43
|
tag
|
33
44
|
end
|
34
45
|
|
46
|
+
# Convert the view to a string by rendering it.
|
47
|
+
#
|
48
|
+
# @return [String] The rendered HTML.
|
35
49
|
def to_s
|
36
50
|
render
|
37
51
|
end
|
@@ -93,11 +93,13 @@ module UltraSettings
|
|
93
93
|
time
|
94
94
|
end
|
95
95
|
|
96
|
+
# @param value [Object] The value to check.
|
96
97
|
# @return [Boolean] true if the value is a numeric type or a string representing a number.
|
97
98
|
def numeric?(value)
|
98
99
|
value.is_a?(Numeric) || (value.is_a?(String) && value.to_s.match?(NUMERIC_REGEX))
|
99
100
|
end
|
100
101
|
|
102
|
+
# @param value [Object] The value to check.
|
101
103
|
# @return [Boolean] true if the value is nil or empty.
|
102
104
|
def blank?(value)
|
103
105
|
return true if value.nil?
|
@@ -109,6 +111,7 @@ module UltraSettings
|
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
114
|
+
# @param value [Object] The value to check.
|
112
115
|
# @return [Boolean] true if the value is not nil and not empty.
|
113
116
|
def present?(value)
|
114
117
|
!blank?(value)
|
@@ -1,16 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module UltraSettings
|
4
|
-
# Helper module for setting up a class to use the config methods
|
4
|
+
# Helper module for setting up a class to use the config methods.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
6
|
+
# @example
|
7
|
+
# class TestClass
|
8
|
+
# extend UltraSettings::ConfigHelper
|
9
|
+
# configuration_class TestConfiguration
|
10
|
+
# end
|
11
|
+
# TestClass.config # => TestConfiguration.instance
|
12
|
+
# TestClass.new.config # => TestConfiguration.instance
|
13
13
|
module ConfigHelper
|
14
|
+
# Define the configuration class and create config methods.
|
15
|
+
#
|
16
|
+
# @param config_class [Class] The configuration class to use.
|
17
|
+
# @return [void]
|
14
18
|
def configuration_class(config_class)
|
15
19
|
define_singleton_method :config do
|
16
20
|
config_class.instance
|
@@ -61,7 +61,7 @@ module UltraSettings
|
|
61
61
|
default: default,
|
62
62
|
default_if: default_if,
|
63
63
|
env_var: construct_env_var(name, env_var),
|
64
|
-
runtime_setting:
|
64
|
+
runtime_setting: construct_runtime_setting(name, runtime_setting),
|
65
65
|
yaml_key: construct_yaml_key(name, yaml_key),
|
66
66
|
static: static,
|
67
67
|
secret: secret
|
@@ -11,10 +11,17 @@ module UltraSettings
|
|
11
11
|
# <h1>Service Configuration</h1>
|
12
12
|
# <%= UltraSettings::ConfigurationView.new(ServiceConfiguration.instance).render %>
|
13
13
|
class ConfigurationView
|
14
|
+
# Initialize the configuration view with a configuration instance.
|
15
|
+
#
|
16
|
+
# @param configuration [UltraSettings::Configuration] The configuration instance to display.
|
14
17
|
def initialize(configuration)
|
15
18
|
@configuration = configuration
|
16
19
|
end
|
17
20
|
|
21
|
+
# Render the HTML for the configuration view.
|
22
|
+
#
|
23
|
+
# @param table_class [String] CSS class for the table element (maintained for backwards compatibility).
|
24
|
+
# @return [String] The rendered HTML.
|
18
25
|
def render(table_class: "")
|
19
26
|
configuration = @configuration
|
20
27
|
html = ViewHelper.erb_template("configuration.html.erb").result(binding)
|
@@ -22,6 +29,9 @@ module UltraSettings
|
|
22
29
|
html
|
23
30
|
end
|
24
31
|
|
32
|
+
# Convert the view to a string by rendering it.
|
33
|
+
#
|
34
|
+
# @return [String] The rendered HTML.
|
25
35
|
def to_s
|
26
36
|
render
|
27
37
|
end
|
@@ -42,14 +52,29 @@ module UltraSettings
|
|
42
52
|
end
|
43
53
|
|
44
54
|
def show_defined_value(label, value, secret)
|
45
|
-
|
46
|
-
|
55
|
+
val = nil
|
56
|
+
icon = nil
|
57
|
+
css_class = nil
|
58
|
+
|
59
|
+
if value.nil?
|
60
|
+
val = "Not set"
|
61
|
+
icon = not_set_icon
|
62
|
+
css_class = "ultra-settings-icon-not-set"
|
47
63
|
elsif secret
|
48
|
-
|
64
|
+
val = secret_value(value)
|
65
|
+
icon = lock_icon
|
66
|
+
css_class = "ultra-settings-icon-secret"
|
49
67
|
else
|
50
|
-
|
68
|
+
val = display_value(value)
|
69
|
+
icon = eye_icon
|
70
|
+
css_class = "ultra-settings-icon-info"
|
51
71
|
end
|
52
|
-
|
72
|
+
|
73
|
+
<<~HTML
|
74
|
+
<dfn class="#{css_class}" title="#{html_escape(val)}" onclick="#{html_escape(open_dialog_script)}" data-label="#{html_escape(label)}">
|
75
|
+
#{icon}
|
76
|
+
</dfn>
|
77
|
+
HTML
|
53
78
|
end
|
54
79
|
|
55
80
|
def secret_value(value)
|
@@ -68,5 +93,69 @@ module UltraSettings
|
|
68
93
|
end
|
69
94
|
path.relative_path_from(root_path)
|
70
95
|
end
|
96
|
+
|
97
|
+
def info_icon(size = 16)
|
98
|
+
<<~HTML
|
99
|
+
<svg width="#{size}" height="#{size}" fill="currentColor" viewBox="0 0 16 16">
|
100
|
+
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
|
101
|
+
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
|
102
|
+
</svg>
|
103
|
+
HTML
|
104
|
+
end
|
105
|
+
|
106
|
+
def not_set_icon(size = 16)
|
107
|
+
<<~HTML
|
108
|
+
<svg width="#{size}" height="#{size}" fill="currentColor" viewBox="0 0 16 16">
|
109
|
+
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
|
110
|
+
<path d="M11.354 4.646a.5.5 0 0 0-.708 0l-6 6a.5.5 0 0 0 .708.708l6-6a.5.5 0 0 0 0-.708"/>
|
111
|
+
</svg>
|
112
|
+
HTML
|
113
|
+
end
|
114
|
+
|
115
|
+
def lock_icon(size = 16)
|
116
|
+
<<~HTML
|
117
|
+
<svg width="#{size}" height="#{size}" fill="currentColor" viewBox="0 0 16 16">
|
118
|
+
<path fill-rule="evenodd" d="M8 0a4 4 0 0 1 4 4v2.05a2.5 2.5 0 0 1 2 2.45v5a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 2 13.5v-5a2.5 2.5 0 0 1 2-2.45V4a4 4 0 0 1 4-4m0 1a3 3 0 0 0-3 3v2h6V4a3 3 0 0 0-3-3"/>
|
119
|
+
</svg>
|
120
|
+
HTML
|
121
|
+
end
|
122
|
+
|
123
|
+
def edit_icon(size = 16)
|
124
|
+
<<~HTML
|
125
|
+
<svg width="#{size}" height="#{size}" fill="currentColor" viewBox="0 0 16 16">
|
126
|
+
<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"/>
|
127
|
+
<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"/>
|
128
|
+
</svg>
|
129
|
+
HTML
|
130
|
+
end
|
131
|
+
|
132
|
+
def eye_icon(size = 16)
|
133
|
+
<<~HTML
|
134
|
+
<svg width="#{size}" height="#{size}" fill="currentColor" viewBox="0 0 16 16">
|
135
|
+
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z"/>
|
136
|
+
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0"/>
|
137
|
+
</svg>
|
138
|
+
HTML
|
139
|
+
end
|
140
|
+
|
141
|
+
def close_icon(size = 16)
|
142
|
+
<<~HTML
|
143
|
+
<svg width="#{size}" height="#{size}" fill="currentColor" viewBox="0 0 16 16">
|
144
|
+
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
|
145
|
+
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>
|
146
|
+
</svg>
|
147
|
+
HTML
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def open_dialog_script
|
153
|
+
<<~JAVASCRIPT.gsub(/\s+/, " ").tr('"', "'")
|
154
|
+
this.closest('.ultra-settings-configuration').querySelector('.ultra-settings-dialog-title').textContent = this.dataset.label;
|
155
|
+
this.closest('.ultra-settings-configuration').querySelector('.ultra-settings-dialog-value').textContent = this.title;
|
156
|
+
this.closest('.ultra-settings-configuration').querySelector('.ultra-settings-dialog').showModal();
|
157
|
+
this.closest('.ultra-settings-configuration').querySelector('.ultra-settings-dialog-close').blur();
|
158
|
+
JAVASCRIPT
|
159
|
+
end
|
71
160
|
end
|
72
161
|
end
|
data/lib/ultra_settings/field.rb
CHANGED
@@ -118,6 +118,7 @@ module UltraSettings
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def runtime_setting_value(settings)
|
121
|
+
return nil if static? || (secret? && !UltraSettings.runtime_settings_secure?)
|
121
122
|
return nil unless settings && runtime_setting
|
122
123
|
|
123
124
|
if type == :array && settings.respond_to?(:array)
|
@@ -5,11 +5,18 @@ 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
|
+
# Initialize a new Rack application for displaying settings.
|
9
|
+
#
|
10
|
+
# @param color_scheme [Symbol, nil] The color scheme to use in the UI (:light, :dark, or :system).
|
8
11
|
def initialize(color_scheme: nil)
|
9
12
|
@webview = nil
|
10
13
|
@color_scheme = color_scheme
|
11
14
|
end
|
12
15
|
|
16
|
+
# Handle Rack requests and return the settings HTML page.
|
17
|
+
#
|
18
|
+
# @param env [Hash] The Rack environment.
|
19
|
+
# @return [Array] A Rack response array [status, headers, body].
|
13
20
|
def call(env)
|
14
21
|
[200, {"content-type" => "text/html; charset=utf8"}, [webview.render_settings]]
|
15
22
|
end
|
@@ -3,26 +3,31 @@
|
|
3
3
|
module UltraSettings
|
4
4
|
# This class is used to represent runtime settings that have not been initialized yet.
|
5
5
|
# You can use this to protect your application from accidentally accessing runtime settings
|
6
|
-
# before they are initialized. Doing this can
|
7
|
-
# engine has not yet been initialized. For instance, if your runtime settings
|
6
|
+
# before they are initialized. Doing this can cause unexpected behavior if the runtime settings
|
7
|
+
# engine has not yet been initialized. For instance, if your runtime settings engine reads from
|
8
8
|
# a database it would not be available until the database connection is established.
|
9
9
|
#
|
10
|
-
# The intention of this class is to set it
|
10
|
+
# The intention of this class is to set it as the runtime settings at the beginning of initialization
|
11
11
|
# and then set the actual runtime settings engine after the initialization is complete. It will
|
12
12
|
# act as a guard to prevent invalid runtime settings backed configurations from being used during
|
13
13
|
# initialization.
|
14
14
|
#
|
15
15
|
# @example
|
16
16
|
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
17
|
+
# UltraSettings.runtime_settings = UltraSettings::UninitializedRuntimeSettings
|
18
|
+
# ActiveSupport.on_load(:active_record) do
|
19
|
+
# UltraSettings.runtime_settings = SuperSettings
|
20
|
+
# end
|
21
21
|
class UninitializedRuntimeSettings
|
22
22
|
class Error < StandardError
|
23
23
|
end
|
24
24
|
|
25
25
|
class << self
|
26
|
+
# Raises an error when attempting to access runtime settings during initialization.
|
27
|
+
#
|
28
|
+
# @param key [String] The key being accessed.
|
29
|
+
# @return [void]
|
30
|
+
# @raise [Error] Always raises an error to prevent access during initialization.
|
26
31
|
def [](key)
|
27
32
|
raise Error.new("Attempt to call runtime setting #{key} during initialization")
|
28
33
|
end
|
@@ -6,14 +6,25 @@ module UltraSettings
|
|
6
6
|
@cache = {}
|
7
7
|
|
8
8
|
class << self
|
9
|
+
# Get an ERB template for rendering.
|
10
|
+
#
|
11
|
+
# @param path [String] The path to the template file.
|
12
|
+
# @return [ERB] The compiled ERB template.
|
9
13
|
def erb_template(path)
|
10
14
|
@cache["erb:#{path}"] ||= ERB.new(read_app_file(path))
|
11
15
|
end
|
12
16
|
|
17
|
+
# Read a file from the app directory.
|
18
|
+
#
|
19
|
+
# @param path [String] The path to the file relative to the app directory.
|
20
|
+
# @return [String] The contents of the file.
|
13
21
|
def read_app_file(path)
|
14
22
|
@cache["file:#{path}"] ||= File.read(File.join(app_dir, path))
|
15
23
|
end
|
16
24
|
|
25
|
+
# Get the app directory path.
|
26
|
+
#
|
27
|
+
# @return [String] The absolute path to the app directory.
|
17
28
|
def app_dir
|
18
29
|
File.expand_path(File.join("..", "..", "app"), __dir__)
|
19
30
|
end
|
@@ -5,18 +5,26 @@ module UltraSettings
|
|
5
5
|
class WebView
|
6
6
|
attr_reader :layout_css
|
7
7
|
|
8
|
+
# Initialize a new WebView with the specified color scheme.
|
9
|
+
#
|
8
10
|
# @param color_scheme [Symbol] The color scheme to use in the UI. This can be `:light`,
|
9
|
-
#
|
11
|
+
# `:dark`, or `:system`. The default is `:light`.
|
10
12
|
def initialize(color_scheme: :light)
|
11
13
|
@color_scheme = (color_scheme || :light).to_sym
|
12
14
|
@layout_template = ViewHelper.erb_template("layout.html.erb")
|
13
15
|
@layout_css = scheme_layout_css(@color_scheme)
|
14
16
|
end
|
15
17
|
|
18
|
+
# Render the complete settings page HTML.
|
19
|
+
#
|
20
|
+
# @return [String] The rendered HTML page.
|
16
21
|
def render_settings
|
17
22
|
@layout_template.result(binding)
|
18
23
|
end
|
19
24
|
|
25
|
+
# Get the content for the settings page.
|
26
|
+
#
|
27
|
+
# @return [String] The HTML content for the settings.
|
20
28
|
def content
|
21
29
|
UltraSettings::ApplicationView.new(color_scheme: @color_scheme).render
|
22
30
|
end
|
@@ -33,11 +33,18 @@ module UltraSettings
|
|
33
33
|
# In addition, the keys are flattened into a one level deep hash with dots
|
34
34
|
# separating the keys.
|
35
35
|
class YamlConfig
|
36
|
+
# Initialize a YAML configuration loader.
|
37
|
+
#
|
38
|
+
# @param path [String, Pathname] The path to the YAML configuration file.
|
39
|
+
# @param environment [String] The environment section to load from the YAML file.
|
36
40
|
def initialize(path, environment)
|
37
41
|
yaml = load_yaml(path)
|
38
42
|
@config = environment_config(yaml, environment)
|
39
43
|
end
|
40
44
|
|
45
|
+
# Convert the loaded configuration to a hash.
|
46
|
+
#
|
47
|
+
# @return [Hash] The flattened configuration hash.
|
41
48
|
def to_h
|
42
49
|
@config
|
43
50
|
end
|
data/lib/ultra_settings.rb
CHANGED
@@ -38,6 +38,7 @@ module UltraSettings
|
|
38
38
|
@mutex = Mutex.new
|
39
39
|
@runtime_settings = nil
|
40
40
|
@runtime_settings_url = nil
|
41
|
+
@runtime_settings_secure = true
|
41
42
|
|
42
43
|
class << self
|
43
44
|
# Adds a configuration to the root namespace. The configuration will be
|
@@ -111,6 +112,7 @@ module UltraSettings
|
|
111
112
|
# Defaults to "development".
|
112
113
|
#
|
113
114
|
# @param value [String] The environment name to use.
|
115
|
+
# @return [void]
|
114
116
|
def yaml_config_env=(value)
|
115
117
|
Configuration.yaml_config_env = value
|
116
118
|
end
|
@@ -128,6 +130,7 @@ module UltraSettings
|
|
128
130
|
# this is a period.
|
129
131
|
#
|
130
132
|
# @param value [String] The delimiter to use.
|
133
|
+
# @return [void]
|
131
134
|
def runtime_setting_delimiter=(value)
|
132
135
|
Configuration.runtime_setting_delimiter = value.to_s
|
133
136
|
end
|
@@ -162,6 +165,9 @@ module UltraSettings
|
|
162
165
|
# Set the object to use for runtime settings. This can be any object that
|
163
166
|
# responds to the [] method. If you are using the `super_settings` gem,
|
164
167
|
# you can set this to `SuperSettings`.
|
168
|
+
#
|
169
|
+
# @param value [#[]] The object to use for runtime settings.
|
170
|
+
# @return [void]
|
165
171
|
attr_writer :runtime_settings
|
166
172
|
|
167
173
|
# Get the object to use for runtime settings.
|
@@ -176,21 +182,46 @@ module UltraSettings
|
|
176
182
|
# URL will be displayed in the web view for fields that support runtime settings.
|
177
183
|
# The URL may contain a `${name}` placeholder that will be replaced with the name
|
178
184
|
# of the setting.
|
185
|
+
#
|
186
|
+
# @param value [String] The URL for changing runtime settings.
|
187
|
+
# @return [void]
|
179
188
|
attr_writer :runtime_settings_url
|
180
189
|
|
181
190
|
# Get the URL for changing runtime settings.
|
182
191
|
#
|
183
192
|
# @param name [String] The name of the setting.
|
193
|
+
# @param type [String] The type of the setting.
|
194
|
+
# @param description [String] The description of the setting.
|
184
195
|
# @return [String, nil]
|
185
196
|
# @api private
|
186
|
-
def runtime_settings_url(name, type)
|
197
|
+
def runtime_settings_url(name: nil, type: nil, description: nil)
|
187
198
|
url = @runtime_settings_url.to_s
|
188
199
|
return nil if url.empty?
|
189
200
|
|
190
|
-
url
|
191
|
-
|
201
|
+
url.gsub("${name}", URI.encode_www_form_component(name.to_s))
|
202
|
+
.gsub("${type}", URI.encode_www_form_component(type.to_s))
|
203
|
+
.gsub("${description}", URI.encode_www_form_component(description.to_s))
|
204
|
+
end
|
205
|
+
|
206
|
+
# Set whether or not the runtime settings engine is considered secure. If this is set
|
207
|
+
# to false, then runtime settings will be disabled for all fields marked as secret.
|
208
|
+
# The default value is true.
|
209
|
+
#
|
210
|
+
# @param value [Boolean] Whether the runtime settings engine is secure.
|
211
|
+
# @return [void]
|
212
|
+
attr_writer :runtime_settings_secure
|
213
|
+
|
214
|
+
# Check if the runtime settings engine is considered secure.
|
215
|
+
#
|
216
|
+
# @return [Boolean]
|
217
|
+
def runtime_settings_secure?
|
218
|
+
@runtime_settings_secure
|
192
219
|
end
|
193
220
|
|
221
|
+
# Set whether fields should be considered secret by default.
|
222
|
+
#
|
223
|
+
# @param value [Boolean] Whether fields should be secret by default.
|
224
|
+
# @return [void]
|
194
225
|
def fields_secret_by_default=(value)
|
195
226
|
Configuration.fields_secret_by_default = value
|
196
227
|
end
|
@@ -245,6 +276,7 @@ module UltraSettings
|
|
245
276
|
unless klass < Configuration
|
246
277
|
raise TypeError.new("Configuration class #{class_name} does not inherit from UltraSettings::Configuration")
|
247
278
|
end
|
279
|
+
|
248
280
|
@configurations[name] = klass
|
249
281
|
end
|
250
282
|
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.7.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: 2025-
|
11
|
+
date: 2025-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|