ultra_settings 2.7.0 → 2.8.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 -0
- data/README.md +1 -1
- data/VERSION +1 -1
- data/app/_config_description.html.erb +30 -0
- data/app/_config_list.html.erb +14 -0
- data/app/_select_menu.html.erb +53 -0
- data/app/application.css +172 -34
- data/app/application.js +108 -25
- data/app/configuration.html.erb +56 -23
- data/app/index.html.erb +21 -16
- data/lib/ultra_settings/application_view.rb +8 -12
- data/lib/ultra_settings/configuration.rb +40 -7
- data/lib/ultra_settings/configuration_view.rb +2 -6
- data/lib/ultra_settings/field.rb +2 -2
- data/lib/ultra_settings/render_helper.rb +28 -0
- data/lib/ultra_settings/view_helper.rb +8 -0
- data/lib/ultra_settings.rb +14 -0
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 846f2c54ef9d4019e4f97ad02dcc962813a29fccc6128fe1e18ef9f263c01c2e
|
|
4
|
+
data.tar.gz: 7d28f71ae610362fd8e2c4e0ffe2ae885d7b9f270fc0e942f41fd7e8daff18fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8829e070b1f37474fc6673804d219d1485b2cb36c5d81f9dcd4b88ff6623bd1f99a5a135adedf4cc2a2f1865ac27d74b8f405b01896aabc3da2b5e41226333f3
|
|
7
|
+
data.tar.gz: 0e906fddfea5764d653beb41c99d534c30b44974a83b8f7e3de1d76dd1656e367fe160743f4ac65ec422bf0e1c7d0c35b28ff2d5e3ce4252bf70d53d0f367709
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ 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.8.0
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added support for setting a description on configuration classes. The class description can serve to document the purpose of the configuration and will be shown in the web UI.
|
|
12
|
+
- Improved menu for selecting configuration classes in the web UI by adding a search box to filter the list of configurations.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Fixed filtering of data sources for configuration classes in the web UI.
|
|
17
|
+
- The YAML source will not be shown if the configuration file is set to nil or false.
|
|
18
|
+
- The runtime settings source will not be shown if the runtime settings engine is not set up.
|
|
19
|
+
- Fields that override the class default for a data source will now correctly show that source.
|
|
20
|
+
|
|
7
21
|
## 2.7.0
|
|
8
22
|
|
|
9
23
|
### Added
|
data/README.md
CHANGED
|
@@ -424,7 +424,7 @@ If you prefer to embed the settings view directly into your own admin tools or d
|
|
|
424
424
|
```erb
|
|
425
425
|
<h1>Configuration</h1>
|
|
426
426
|
|
|
427
|
-
<%= UltraSettings::ApplicationView.new.render
|
|
427
|
+
<%= UltraSettings::ApplicationView.new.render %>
|
|
428
428
|
```
|
|
429
429
|
|
|
430
430
|
This approach allows for seamless integration of the settings UI into your application's admin interface, leveraging your existing authentication and authorization mechanisms. The settings are rendered with navigation handled by an HTML select element. You can specify the CSS classes for the select element to match your own application styles..
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.8.0
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<% config_class = configuration.class
|
|
2
|
+
has_config_file = config_class.configuration_file.is_a?(Pathname) && config_class.fields.any?(&:yaml_key) %>
|
|
3
|
+
|
|
4
|
+
<% if config_class.description || has_config_file %>
|
|
5
|
+
<div class="ultra-settings-description-container">
|
|
6
|
+
<% if config_class.description %>
|
|
7
|
+
<div class="ultra-settings-description">
|
|
8
|
+
<%= html_escape(config_class.description).gsub("\n", "<br>") %>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<% if has_config_file %>
|
|
13
|
+
<div class="ultra-settings-description">
|
|
14
|
+
<span class="ultra-settings-config-file-label">
|
|
15
|
+
Configuration file:
|
|
16
|
+
</span>
|
|
17
|
+
|
|
18
|
+
<code class="ultra-settings-config-file-path">
|
|
19
|
+
<%= html_escape(relative_path(configuration.class.configuration_file)) %>
|
|
20
|
+
</code>
|
|
21
|
+
|
|
22
|
+
<% unless configuration.class.configuration_file&.exist? %>
|
|
23
|
+
<span class="ultra-settings-file-not-found">
|
|
24
|
+
(file does not exist)
|
|
25
|
+
</span>
|
|
26
|
+
<% end %>
|
|
27
|
+
</div>
|
|
28
|
+
<% end %>
|
|
29
|
+
</div>
|
|
30
|
+
<% end %>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div class="ultra-settings-configuration-list" style="display:none;">
|
|
2
|
+
<% configurations.each do |configuration| %>
|
|
3
|
+
<div class="ultra-settings-configuration-summary">
|
|
4
|
+
<a
|
|
5
|
+
href="#<%= html_escape(configuration.class.name) %>"
|
|
6
|
+
class="ultra-settings-configuration-title"
|
|
7
|
+
>
|
|
8
|
+
<%= html_escape(configuration.class.name) %>
|
|
9
|
+
</a>
|
|
10
|
+
|
|
11
|
+
<p><%= html_escape(configuration.class.description) %></p>
|
|
12
|
+
</div>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<div class="ultra-settings-dropdown" id="config-dropdown">
|
|
2
|
+
<button
|
|
3
|
+
type="button"
|
|
4
|
+
class="ultra-settings-dropdown-button"
|
|
5
|
+
id="config-dropdown-button"
|
|
6
|
+
>
|
|
7
|
+
Select Configuration
|
|
8
|
+
</button>
|
|
9
|
+
|
|
10
|
+
<div
|
|
11
|
+
class="ultra-settings-dropdown-menu"
|
|
12
|
+
id="config-dropdown-menu"
|
|
13
|
+
style="display: none;"
|
|
14
|
+
>
|
|
15
|
+
<div class="ultra-settings-search-container">
|
|
16
|
+
<input
|
|
17
|
+
type="text"
|
|
18
|
+
id="config-search"
|
|
19
|
+
placeholder="Search..."
|
|
20
|
+
autocomplete="off"
|
|
21
|
+
>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<ul class="ultra-settings-dropdown-list" id="config-list">
|
|
25
|
+
<% configurations.each do |config| %>
|
|
26
|
+
<% config_text = [
|
|
27
|
+
config.class.name,
|
|
28
|
+
config.class.description
|
|
29
|
+
]
|
|
30
|
+
config.class.fields.each do |field|
|
|
31
|
+
config_text << field.name
|
|
32
|
+
config_text << field.description
|
|
33
|
+
config_text << field.env_var
|
|
34
|
+
config_text << field.runtime_setting
|
|
35
|
+
end
|
|
36
|
+
search_text = config_text.compact.join(" ").downcase %>
|
|
37
|
+
|
|
38
|
+
<li
|
|
39
|
+
class="ultra-settings-dropdown-item"
|
|
40
|
+
data-value="config-<%= html_escape(config.class.name) %>"
|
|
41
|
+
data-label="<%= html_escape(config.class.name) %>"
|
|
42
|
+
data-search="<%= html_escape(search_text) %>"
|
|
43
|
+
>
|
|
44
|
+
<span class="ultra-settings-check-icon"></span>
|
|
45
|
+
|
|
46
|
+
<span class="ultra-settings-config-name">
|
|
47
|
+
<%= html_escape(config.class.name) %>
|
|
48
|
+
</span>
|
|
49
|
+
</li>
|
|
50
|
+
<% end %>
|
|
51
|
+
</ul>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
data/app/application.css
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
margin-bottom: 1rem;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
.ultra-settings-
|
|
6
|
-
margin: 0;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.ultra-settings-config-file {
|
|
5
|
+
.ultra-settings-description-container {
|
|
10
6
|
margin-bottom: 1.5rem;
|
|
11
|
-
|
|
12
|
-
background-color: var(--config-file-bg-color);
|
|
7
|
+
line-height: 1.5;
|
|
13
8
|
border: 1px solid var(--config-file-border-color);
|
|
14
9
|
border-radius: 0.375rem;
|
|
10
|
+
padding: 1rem 1rem 0 1rem;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ultra-settings-description {
|
|
14
|
+
margin-bottom: 1rem;
|
|
15
|
+
color: var(--description-color);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
.ultra-settings-config-file-label {
|
|
18
|
-
font-weight:
|
|
19
|
-
color: var(--
|
|
20
|
-
margin-right: 0.5rem;
|
|
19
|
+
font-weight: 500;
|
|
20
|
+
color: var(--description-color);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
.ultra-settings-config-file-path {
|
|
@@ -184,9 +184,9 @@ code.ultra-settings-field-data-value {
|
|
|
184
184
|
letter-spacing: 0.025em;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
.ultra-settings-source-
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
.ultra-settings-source-indicator::before {
|
|
188
|
+
content: "● ";
|
|
189
|
+
font-size: 1rem;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
.ultra-settings-icon-info {
|
|
@@ -218,27 +218,6 @@ code.ultra-settings-field-data-value {
|
|
|
218
218
|
opacity: 1;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
.ultra-settings-select {
|
|
222
|
-
display: inline-block;
|
|
223
|
-
padding: .375rem 2.25rem .375rem .75rem;
|
|
224
|
-
-moz-padding-start: calc(0.75rem - 3px);
|
|
225
|
-
font-size: 1rem;
|
|
226
|
-
font-weight: 400;
|
|
227
|
-
line-height: 1.5;
|
|
228
|
-
color: var(--form-control-color);
|
|
229
|
-
background-color: var(--form-control-bg-color);
|
|
230
|
-
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");
|
|
231
|
-
background-repeat: no-repeat;
|
|
232
|
-
background-position: right .75rem center;
|
|
233
|
-
background-size: 16px 12px;
|
|
234
|
-
border: 1px solid var(--form-control-border-color);
|
|
235
|
-
border-radius: .25rem;
|
|
236
|
-
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
|
237
|
-
-webkit-appearance: none;
|
|
238
|
-
-moz-appearance: none;
|
|
239
|
-
appearance: none;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
221
|
.ultra-settings-dialog {
|
|
243
222
|
min-width: 20rem;
|
|
244
223
|
padding: 0;
|
|
@@ -273,4 +252,163 @@ code.ultra-settings-field-data-value {
|
|
|
273
252
|
padding: 1rem;
|
|
274
253
|
background-color: var(--background-color);
|
|
275
254
|
color: var(--text-color);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* Dropdown Styles */
|
|
258
|
+
.ultra-settings-dropdown {
|
|
259
|
+
position: relative;
|
|
260
|
+
display: inline-block;
|
|
261
|
+
width: 100%;
|
|
262
|
+
max-width: 400px;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.ultra-settings-dropdown-button {
|
|
266
|
+
width: 100%;
|
|
267
|
+
text-align: left;
|
|
268
|
+
padding: 0.5rem 1rem;
|
|
269
|
+
font-size: 1.25rem;
|
|
270
|
+
font-weight: 500;
|
|
271
|
+
background-color: var(--form-control-bg-color);
|
|
272
|
+
color: var(--form-control-color);
|
|
273
|
+
border: 1px solid var(--form-control-border-color);
|
|
274
|
+
border-radius: 0.375rem;
|
|
275
|
+
cursor: pointer;
|
|
276
|
+
display: flex;
|
|
277
|
+
justify-content: space-between;
|
|
278
|
+
align-items: center;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.ultra-settings-dropdown-button::after {
|
|
282
|
+
content: "";
|
|
283
|
+
display: inline-block;
|
|
284
|
+
width: 0;
|
|
285
|
+
height: 0;
|
|
286
|
+
margin-left: 0.5rem;
|
|
287
|
+
vertical-align: middle;
|
|
288
|
+
border-top: 4px solid;
|
|
289
|
+
border-right: 4px solid transparent;
|
|
290
|
+
border-left: 4px solid transparent;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.ultra-settings-dropdown-menu {
|
|
294
|
+
position: absolute;
|
|
295
|
+
top: 100%;
|
|
296
|
+
left: 0;
|
|
297
|
+
z-index: 1000;
|
|
298
|
+
display: none;
|
|
299
|
+
min-width: 100%;
|
|
300
|
+
padding: 0.5rem 0;
|
|
301
|
+
margin: 0.125rem 0 0;
|
|
302
|
+
font-size: 1rem;
|
|
303
|
+
color: var(--text-color);
|
|
304
|
+
text-align: left;
|
|
305
|
+
list-style: none;
|
|
306
|
+
background-color: var(--form-control-bg-color);
|
|
307
|
+
background-clip: padding-box;
|
|
308
|
+
border: 1px solid var(--form-control-border-color);
|
|
309
|
+
border-radius: 0.375rem;
|
|
310
|
+
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.ultra-settings-search-container {
|
|
314
|
+
padding: 0.5rem 1rem;
|
|
315
|
+
border-bottom: 1px solid var(--form-control-border-color);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
#config-search {
|
|
319
|
+
width: 100%;
|
|
320
|
+
padding: 0.375rem 0.75rem;
|
|
321
|
+
font-size: 0.875rem;
|
|
322
|
+
line-height: 1.5;
|
|
323
|
+
color: var(--form-control-color);
|
|
324
|
+
background-color: var(--value-bg-color);
|
|
325
|
+
background-clip: padding-box;
|
|
326
|
+
border: 1px solid var(--form-control-border-color);
|
|
327
|
+
border-radius: 0.25rem;
|
|
328
|
+
box-sizing: border-box;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.ultra-settings-dropdown-list {
|
|
332
|
+
list-style: none;
|
|
333
|
+
padding: 0;
|
|
334
|
+
margin: 0;
|
|
335
|
+
max-height: 300px;
|
|
336
|
+
overflow-y: auto;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.ultra-settings-dropdown-item {
|
|
340
|
+
display: flex;
|
|
341
|
+
align-items: center;
|
|
342
|
+
padding: 0.5rem 1rem;
|
|
343
|
+
clear: both;
|
|
344
|
+
font-weight: 400;
|
|
345
|
+
color: var(--form-control-color);
|
|
346
|
+
text-align: inherit;
|
|
347
|
+
white-space: nowrap;
|
|
348
|
+
background-color: transparent;
|
|
349
|
+
border: 0;
|
|
350
|
+
cursor: pointer;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.ultra-settings-dropdown-item:hover {
|
|
354
|
+
background-color: var(--field-header-bg-color);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.ultra-settings-check-icon {
|
|
358
|
+
width: 1.5rem;
|
|
359
|
+
display: inline-block;
|
|
360
|
+
text-align: center;
|
|
361
|
+
font-weight: bold;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.ultra-settings-dropdown-item.selected .ultra-settings-check-icon::before {
|
|
365
|
+
content: "✓";
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.ultra-settings-title {
|
|
369
|
+
margin: 0;
|
|
370
|
+
font-size: 1.25rem;
|
|
371
|
+
font-weight: 500;
|
|
372
|
+
color: var(--text-color);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/* Configuration List Styles */
|
|
376
|
+
.ultra-settings-configuration-list {
|
|
377
|
+
display: grid;
|
|
378
|
+
grid-template-columns: repeat(auto-fill, minmax(max(300px, 30%), 1fr));
|
|
379
|
+
gap: 1.5rem;
|
|
380
|
+
margin-top: 1.5rem;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.ultra-settings-configuration-summary {
|
|
384
|
+
background-color: var(--field-bg-color);
|
|
385
|
+
border: 1px solid var(--field-border-color);
|
|
386
|
+
border-radius: 0.5rem;
|
|
387
|
+
padding: 1.5rem;
|
|
388
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
389
|
+
overflow: hidden;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.ultra-settings-configuration-summary:hover {
|
|
393
|
+
transform: translateY(-2px);
|
|
394
|
+
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.1);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.ultra-settings-configuration-title {
|
|
398
|
+
display: block;
|
|
399
|
+
font-size: 1.25rem;
|
|
400
|
+
font-weight: 600;
|
|
401
|
+
color: var(--description-color);
|
|
402
|
+
text-decoration: none;
|
|
403
|
+
margin-bottom: 0.75rem;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.ultra-settings-configuration-title:hover {
|
|
407
|
+
text-decoration: underline;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.ultra-settings-configuration-summary p {
|
|
411
|
+
margin: 0;
|
|
412
|
+
color: var(--description-color);
|
|
413
|
+
line-height: 1.5;
|
|
276
414
|
}
|
data/app/application.js
CHANGED
|
@@ -1,41 +1,124 @@
|
|
|
1
1
|
document.addEventListener("DOMContentLoaded", () => {
|
|
2
|
-
const
|
|
2
|
+
const dropdown = document.getElementById("config-dropdown");
|
|
3
|
+
const button = document.getElementById("config-dropdown-button");
|
|
4
|
+
const menu = document.getElementById("config-dropdown-menu");
|
|
5
|
+
const searchInput = document.getElementById("config-search");
|
|
6
|
+
const items = document.querySelectorAll(".ultra-settings-dropdown-item");
|
|
7
|
+
const configurations = document.querySelectorAll(".ultra-settings-configuration");
|
|
8
|
+
const configList = document.querySelector(".ultra-settings-configuration-list");
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
// If no dropdown, we might be in single config mode or no configs.
|
|
11
|
+
if (!dropdown) {
|
|
12
|
+
// If there is exactly one configuration, show it.
|
|
13
|
+
if (configurations.length === 1) {
|
|
14
|
+
configurations[0].style.display = "block";
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
7
18
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
const toggleMenu = () => {
|
|
20
|
+
const isVisible = menu.style.display === "block";
|
|
21
|
+
menu.style.display = isVisible ? "none" : "block";
|
|
22
|
+
if (!isVisible) {
|
|
23
|
+
searchInput.value = "";
|
|
24
|
+
filterItems("");
|
|
25
|
+
searchInput.focus();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const closeMenu = () => {
|
|
30
|
+
menu.style.display = "none";
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const filterItems = (query) => {
|
|
34
|
+
const lowerQuery = query.toLowerCase();
|
|
35
|
+
items.forEach(item => {
|
|
36
|
+
const label = item.getAttribute("data-search").toLowerCase();
|
|
37
|
+
if (label.includes(lowerQuery)) {
|
|
38
|
+
item.style.display = "flex";
|
|
12
39
|
} else {
|
|
13
|
-
|
|
40
|
+
item.style.display = "none";
|
|
14
41
|
}
|
|
15
42
|
});
|
|
16
|
-
}
|
|
43
|
+
};
|
|
17
44
|
|
|
18
|
-
|
|
45
|
+
const showConfigList = () => {
|
|
46
|
+
if (configList) configList.style.display = "grid";
|
|
47
|
+
configurations.forEach(config => config.style.display = "none");
|
|
48
|
+
items.forEach(item => item.classList.remove("selected"));
|
|
49
|
+
button.textContent = "Select Configuration";
|
|
50
|
+
closeMenu();
|
|
51
|
+
};
|
|
19
52
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
53
|
+
const showConfig = (configId) => {
|
|
54
|
+
if (configList) configList.style.display = "none";
|
|
55
|
+
|
|
56
|
+
configurations.forEach(config => {
|
|
57
|
+
config.style.display = config.id === configId ? "block" : "none";
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
items.forEach(item => {
|
|
61
|
+
if (item.getAttribute("data-value") === configId) {
|
|
62
|
+
item.classList.add("selected");
|
|
63
|
+
button.textContent = item.getAttribute("data-label");
|
|
64
|
+
} else {
|
|
65
|
+
item.classList.remove("selected");
|
|
27
66
|
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
closeMenu();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Event Listeners
|
|
73
|
+
button.addEventListener("click", (e) => {
|
|
74
|
+
e.stopPropagation();
|
|
75
|
+
toggleMenu();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
document.addEventListener("click", (e) => {
|
|
79
|
+
if (!dropdown.contains(e.target)) {
|
|
80
|
+
closeMenu();
|
|
28
81
|
}
|
|
82
|
+
});
|
|
29
83
|
|
|
30
|
-
|
|
31
|
-
|
|
84
|
+
searchInput.addEventListener("input", (e) => {
|
|
85
|
+
filterItems(e.target.value);
|
|
86
|
+
});
|
|
32
87
|
|
|
33
|
-
|
|
88
|
+
items.forEach(item => {
|
|
89
|
+
item.addEventListener("click", () => {
|
|
90
|
+
const configId = item.getAttribute("data-value");
|
|
91
|
+
const hash = configId.replace(/^config-/, "");
|
|
34
92
|
|
|
93
|
+
if (item.classList.contains("selected")) {
|
|
94
|
+
// Toggle off: clear hash
|
|
95
|
+
history.pushState("", document.title, window.location.pathname + window.location.search);
|
|
96
|
+
handleHashChange();
|
|
97
|
+
} else {
|
|
98
|
+
window.location.hash = hash;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
35
102
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
103
|
+
// Initial Load & Hash Change
|
|
104
|
+
const handleHashChange = () => {
|
|
105
|
+
const hash = window.location.hash.replace(/^#/, "");
|
|
106
|
+
if (hash) {
|
|
107
|
+
const configId = `config-${hash}`;
|
|
108
|
+
// Check if config exists
|
|
109
|
+
const exists = Array.from(items).some(item => item.getAttribute("data-value") === configId);
|
|
110
|
+
if (exists) {
|
|
111
|
+
showConfig(configId);
|
|
112
|
+
} else {
|
|
113
|
+
showConfigList();
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
showConfigList();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
window.addEventListener("hashchange", handleHashChange);
|
|
39
121
|
|
|
40
|
-
|
|
122
|
+
// Run once on load
|
|
123
|
+
handleHashChange();
|
|
41
124
|
});
|
data/app/configuration.html.erb
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
<div class="ultra-settings-block">
|
|
2
|
-
|
|
3
|
-
<div class="ultra-settings-config-file">
|
|
4
|
-
<span class="ultra-settings-config-file-label">Configuration File:</span>
|
|
5
|
-
<code class="ultra-settings-config-file-path"><%= html_escape(relative_path(configuration.class.configuration_file)) %></code>
|
|
6
|
-
<% unless configuration.class.configuration_file&.exist? %>
|
|
7
|
-
<span class="ultra-settings-file-not-found">(File does not exist)</span>
|
|
8
|
-
<% end %>
|
|
9
|
-
</div>
|
|
10
|
-
<% end %>
|
|
2
|
+
<%= render_partial "config_description", configuration: configuration %>
|
|
11
3
|
|
|
12
4
|
<div class="ultra-settings-fields">
|
|
13
5
|
<% configuration.class.fields.each do |field| %>
|
|
14
6
|
<% source = configuration.__source__(field.name) %>
|
|
7
|
+
|
|
15
8
|
<div class="ultra-settings-field">
|
|
16
9
|
<div class="ultra-settings-field-header">
|
|
17
10
|
<div class="ultra-settings-field-name">
|
|
18
11
|
<code><%= html_escape(field.name) %></code>
|
|
12
|
+
|
|
19
13
|
<% if field.secret? %>
|
|
20
|
-
<span class="ultra-settings-field-badge ultra-settings-badge-secret">
|
|
14
|
+
<span class="ultra-settings-field-badge ultra-settings-badge-secret">
|
|
15
|
+
secret
|
|
16
|
+
</span>
|
|
21
17
|
<% end %>
|
|
18
|
+
|
|
22
19
|
<% if field.static? %>
|
|
23
|
-
<span class="ultra-settings-field-badge ultra-settings-badge-static">
|
|
20
|
+
<span class="ultra-settings-field-badge ultra-settings-badge-static">
|
|
21
|
+
static
|
|
22
|
+
</span>
|
|
24
23
|
<% end %>
|
|
25
24
|
</div>
|
|
25
|
+
|
|
26
26
|
<div class="ultra-settings-field-type">
|
|
27
27
|
<%= html_escape(field.type) %>
|
|
28
28
|
</div>
|
|
@@ -32,15 +32,20 @@
|
|
|
32
32
|
<% if configuration[field.name].nil? %>
|
|
33
33
|
<span class="ultra-settings-nil-value">nil</span>
|
|
34
34
|
<% elsif field.secret? %>
|
|
35
|
-
<code class="ultra-settings-field-data-value"
|
|
35
|
+
<code class="ultra-settings-field-data-value">
|
|
36
|
+
<%= html_escape(secret_value(configuration[field.name])) %>
|
|
37
|
+
</code>
|
|
36
38
|
<% else %>
|
|
37
|
-
<code class="ultra-settings-field-data-value"
|
|
39
|
+
<code class="ultra-settings-field-data-value">
|
|
40
|
+
<%= html_escape(display_value(configuration[field.name])) %>
|
|
41
|
+
</code>
|
|
38
42
|
<% end %>
|
|
39
43
|
</div>
|
|
40
44
|
|
|
41
45
|
<% unless field.description.to_s.empty? %>
|
|
42
46
|
<div class="ultra-settings-field-description">
|
|
43
47
|
<%= info_icon %>
|
|
48
|
+
|
|
44
49
|
<div class="ultra-settings-description-text">
|
|
45
50
|
<%= html_escape(field.description) %>
|
|
46
51
|
</div>
|
|
@@ -48,61 +53,84 @@
|
|
|
48
53
|
<% end %>
|
|
49
54
|
|
|
50
55
|
<div class="ultra-settings-field-sources">
|
|
51
|
-
<%
|
|
56
|
+
<% sources = configuration.__available_sources__(field.name) %>
|
|
57
|
+
<% if sources.include?(:env) %>
|
|
52
58
|
<div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :env %>">
|
|
53
59
|
<span class="ultra-settings-source-type">
|
|
54
60
|
Environment Variable
|
|
55
61
|
</span>
|
|
62
|
+
|
|
56
63
|
<code class="ultra-settings-source-value">
|
|
57
64
|
<%= field.env_var %>
|
|
58
65
|
<%= show_defined_value(field.env_var, configuration.__value_from_source__(field.name, :env), field.secret?) %>
|
|
59
66
|
</code>
|
|
67
|
+
|
|
60
68
|
<% if source == :env %>
|
|
61
|
-
<span class="ultra-settings-source-indicator">
|
|
69
|
+
<span class="ultra-settings-source-indicator">
|
|
70
|
+
Currently active
|
|
71
|
+
</span>
|
|
62
72
|
<% end %>
|
|
63
73
|
</div>
|
|
64
74
|
<% end %>
|
|
65
75
|
|
|
66
|
-
<% if
|
|
76
|
+
<% if sources.include?(:settings) %>
|
|
67
77
|
<div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :settings %>">
|
|
68
78
|
<span class="ultra-settings-source-type">Runtime Setting</span>
|
|
79
|
+
|
|
69
80
|
<code class="ultra-settings-source-value">
|
|
70
81
|
<%= field.runtime_setting %>
|
|
71
82
|
<%= show_defined_value(field.runtime_setting, configuration.__value_from_source__(field.name, :settings), field.secret?) %>
|
|
72
83
|
</code>
|
|
84
|
+
|
|
73
85
|
<% if source == :settings %>
|
|
74
|
-
<span class="ultra-settings-source-indicator">
|
|
86
|
+
<span class="ultra-settings-source-indicator">
|
|
87
|
+
Currently active
|
|
88
|
+
</span>
|
|
75
89
|
<% end %>
|
|
90
|
+
|
|
76
91
|
<% edit_url = UltraSettings.runtime_settings_url(name: field.runtime_setting, type: field.type, description: field.description) %>
|
|
92
|
+
|
|
77
93
|
<% if edit_url %>
|
|
78
|
-
<a
|
|
94
|
+
<a
|
|
95
|
+
href="<%= html_escape(edit_url) %>"
|
|
96
|
+
class="ultra-settings-edit-link"
|
|
97
|
+
title="Edit <%= html_escape(field.runtime_setting) %>"
|
|
98
|
+
>
|
|
79
99
|
<%= edit_icon %>
|
|
80
100
|
</a>
|
|
81
101
|
<% end %>
|
|
82
102
|
</div>
|
|
83
103
|
<% end %>
|
|
84
104
|
|
|
85
|
-
<% if
|
|
105
|
+
<% if sources.include?(:yaml) %>
|
|
86
106
|
<div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :yaml %>">
|
|
87
107
|
<span class="ultra-settings-source-type">Configuration File</span>
|
|
108
|
+
|
|
88
109
|
<code class="ultra-settings-source-value">
|
|
89
110
|
<%= field.yaml_key %>
|
|
90
111
|
<%= show_defined_value(field.yaml_key, configuration.__value_from_source__(field.name, :yaml), field.secret?) %>
|
|
91
112
|
</code>
|
|
113
|
+
|
|
92
114
|
<% if source == :yaml %>
|
|
93
|
-
<span class="ultra-settings-source-indicator">
|
|
115
|
+
<span class="ultra-settings-source-indicator">
|
|
116
|
+
Currently active
|
|
117
|
+
</span>
|
|
94
118
|
<% end %>
|
|
95
119
|
</div>
|
|
96
120
|
<% end %>
|
|
97
121
|
|
|
98
|
-
<% if
|
|
122
|
+
<% if sources.include?(:default) || source == :default %>
|
|
99
123
|
<div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :default %>">
|
|
100
124
|
<span class="ultra-settings-source-type">Default Value</span>
|
|
125
|
+
|
|
101
126
|
<code class="ultra-settings-source-value">
|
|
102
127
|
<%= show_defined_value("Default Value", field.default, field.secret?) %>
|
|
103
128
|
</code>
|
|
129
|
+
|
|
104
130
|
<% if source == :default %>
|
|
105
|
-
<span class="ultra-settings-source-indicator">
|
|
131
|
+
<span class="ultra-settings-source-indicator">
|
|
132
|
+
Currently active
|
|
133
|
+
</span>
|
|
106
134
|
<% end %>
|
|
107
135
|
</div>
|
|
108
136
|
<% end %>
|
|
@@ -114,10 +142,15 @@
|
|
|
114
142
|
<dialog class="ultra-settings-dialog" closedby="any">
|
|
115
143
|
<div class="ultra-settings-dialog-header">
|
|
116
144
|
<div class="ultra-settings-dialog-title"></div>
|
|
117
|
-
|
|
145
|
+
|
|
146
|
+
<button
|
|
147
|
+
class="ultra-settings-dialog-close"
|
|
148
|
+
onclick="this.closest('.ultra-settings-dialog').close();"
|
|
149
|
+
>
|
|
118
150
|
<%= close_icon %>
|
|
119
151
|
</button>
|
|
120
152
|
</div>
|
|
153
|
+
|
|
121
154
|
<div class="ultra-settings-dialog-body">
|
|
122
155
|
<code class="ultra-settings-field-data-value ultra-settings-dialog-value"></code>
|
|
123
156
|
</div>
|
data/app/index.html.erb
CHANGED
|
@@ -2,25 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
<div class="ultra-settings">
|
|
4
4
|
<div class="ultra-settings-nav">
|
|
5
|
-
|
|
6
|
-
<select class="<%= html_escape(select_class) %>" size="1" id="config-selector">
|
|
7
|
-
<% UltraSettings.__configuration_names__.sort.each do |name| %>
|
|
8
|
-
<% configuration = UltraSettings.send(name) %>
|
|
9
|
-
<% next if configuration.class.fields.empty? %>
|
|
5
|
+
<% configurations = UltraSettings.__configurations__.reject { |config| config.class.fields.empty? }.sort_by { |config| config.class.name.downcase } %>
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
<% if configurations.size == 1 %>
|
|
8
|
+
<h2 class="ultra-settings-title">
|
|
9
|
+
<%= html_escape(configurations.first.class.name) %>
|
|
10
|
+
</h2>
|
|
11
|
+
<% else %>
|
|
12
|
+
<%= render_partial "select_menu", configurations: configurations %>
|
|
13
|
+
<% end %>
|
|
15
14
|
</div>
|
|
16
15
|
|
|
17
|
-
<%
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
<% if configurations.size == 1 %>
|
|
17
|
+
<%= UltraSettings::ConfigurationView.new(configurations.first).render(table_class: table_class) %>
|
|
18
|
+
<% else %>
|
|
19
|
+
<%= render_partial "config_list", configurations: configurations %>
|
|
20
|
+
<% configurations.each do |configuration| %>
|
|
21
|
+
<div
|
|
22
|
+
class="ultra-settings-configuration"
|
|
23
|
+
id="config-<%= html_escape(configuration.class.name) %>"
|
|
24
|
+
style="display:none;"
|
|
25
|
+
>
|
|
26
|
+
<%= UltraSettings::ConfigurationView.new(configuration).render(table_class: table_class) %>
|
|
27
|
+
</div>
|
|
28
|
+
<% end %>
|
|
24
29
|
<% end %>
|
|
25
30
|
</div>
|
|
26
31
|
|
|
@@ -4,15 +4,15 @@ module UltraSettings
|
|
|
4
4
|
# This class can render information about all configurations. It is used by the bundled
|
|
5
5
|
# web UI, but you can use it to embed the configuration information in your own web pages.
|
|
6
6
|
#
|
|
7
|
-
# The output will be a simple HTML drop down
|
|
8
|
-
#
|
|
9
|
-
# the `select_class` option to the `render` method. By default the select element has
|
|
10
|
-
# the class `ultra-settings-select`.
|
|
7
|
+
# The output will be a simple HTML drop down menu that can be used to select the configuration
|
|
8
|
+
# you want to see.
|
|
11
9
|
#
|
|
12
10
|
# @example
|
|
13
11
|
# <h1>Application Configuration</h1>
|
|
14
|
-
# <%= UltraSettings::ApplicationView.new.render
|
|
12
|
+
# <%= UltraSettings::ApplicationView.new.render %>
|
|
15
13
|
class ApplicationView
|
|
14
|
+
include RenderHelper
|
|
15
|
+
|
|
16
16
|
attr_reader :css
|
|
17
17
|
|
|
18
18
|
# Initialize the application view with a color scheme.
|
|
@@ -25,10 +25,10 @@ module UltraSettings
|
|
|
25
25
|
|
|
26
26
|
# Render the HTML for the configuration settings UI.
|
|
27
27
|
#
|
|
28
|
-
# @param select_class [String]
|
|
29
|
-
# @param table_class [String]
|
|
28
|
+
# @param select_class [String] Deprecated; no longer used.
|
|
29
|
+
# @param table_class [String] Deprecated; no longer used.
|
|
30
30
|
# @return [String] The rendered HTML.
|
|
31
|
-
def render(select_class:
|
|
31
|
+
def render(select_class: nil, table_class: nil)
|
|
32
32
|
html = ViewHelper.erb_template("index.html.erb").result(binding)
|
|
33
33
|
html = html.html_safe if html.respond_to?(:html_safe)
|
|
34
34
|
html
|
|
@@ -52,10 +52,6 @@ module UltraSettings
|
|
|
52
52
|
|
|
53
53
|
private
|
|
54
54
|
|
|
55
|
-
def html_escape(value)
|
|
56
|
-
ERB::Util.html_escape(value)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
55
|
def javascript
|
|
60
56
|
ViewHelper.read_app_file("application.js")
|
|
61
57
|
end
|
|
@@ -9,8 +9,20 @@ module UltraSettings
|
|
|
9
9
|
|
|
10
10
|
@env_var_prefix = nil
|
|
11
11
|
@runtime_setting_prefix = nil
|
|
12
|
+
@description = nil
|
|
12
13
|
|
|
13
14
|
class << self
|
|
15
|
+
# Set a description for the configuration. This is optional. It will be displayed
|
|
16
|
+
# in the web UI if provided. On large projects with many configurations, this can
|
|
17
|
+
# help identify the purpose of each configuration.
|
|
18
|
+
#
|
|
19
|
+
# @param text [String] The description text.
|
|
20
|
+
# @return [void]
|
|
21
|
+
def description(text = nil)
|
|
22
|
+
@description = text.to_s.strip unless text.nil?
|
|
23
|
+
@description
|
|
24
|
+
end
|
|
25
|
+
|
|
14
26
|
# Define a field on the configuration. This will create a getter method for the field.
|
|
15
27
|
# The field value will be read from the environment, runtime settings, or a YAML file
|
|
16
28
|
# and coerced to the specified type. Empty strings will be converted to nil.
|
|
@@ -27,14 +39,19 @@ module UltraSettings
|
|
|
27
39
|
# @param static [Boolean] If true, the field value should never be changed. This is useful for
|
|
28
40
|
# fields that are used at startup to set static values in the application. Static field cannot
|
|
29
41
|
# be read from runtime settings.
|
|
30
|
-
# @param
|
|
42
|
+
# @param secret [Boolean, Proc] If true, the field value will be obscured in the output of
|
|
43
|
+
# to_hash. If a proc is provided, it will be called to determine if the field is secret.
|
|
44
|
+
# @param runtime_setting [String, Symbol, Boolean] The name of the runtime setting to use for the field.
|
|
31
45
|
# By default this will be the underscored name of the class plus a dot plus the field name
|
|
32
|
-
# (i.e. MyServiceConfiguration#foo becomes "my_service.foo").
|
|
33
|
-
#
|
|
46
|
+
# (i.e. MyServiceConfiguration#foo becomes "my_service.foo"). If set to false, runtime settings
|
|
47
|
+
# will be ignored for this field. This can be set to true to use the default name.
|
|
48
|
+
# @param env_var [String, Symbol, Boolean] The name of the environment variable to use for the field.
|
|
34
49
|
# By default this will be the underscored name of the class plus an underscore plus the field name
|
|
35
|
-
# all in uppercase (i.e. MyServiceConfiguration#foo becomes "MY_SERVICE_FOO").
|
|
36
|
-
#
|
|
37
|
-
#
|
|
50
|
+
# all in uppercase (i.e. MyServiceConfiguration#foo becomes "MY_SERVICE_FOO"). If set to false,
|
|
51
|
+
# environment variables will be ignored for this field. This can be set to true to use the default name.
|
|
52
|
+
# @param yaml_key [String, Symbol, Boolean] The name of the YAML key to use for the field. By default
|
|
53
|
+
# this is the name of the field. If set to false, YAML configuration will be ignored for this field.
|
|
54
|
+
# This can be set to true to use the default name.
|
|
38
55
|
# @return [void]
|
|
39
56
|
def field(name, type: :string, description: nil, default: nil, default_if: nil, static: nil, secret: nil, runtime_setting: nil, env_var: nil, yaml_key: nil)
|
|
40
57
|
name = name.to_s
|
|
@@ -145,7 +162,7 @@ module UltraSettings
|
|
|
145
162
|
# directory (i.e. MyServiceConfiguration has a default config path of
|
|
146
163
|
# "my_service.yml").
|
|
147
164
|
#
|
|
148
|
-
# @param value [String, Pathname]
|
|
165
|
+
# @param value [String, Pathname, false, nil]
|
|
149
166
|
# @return [void]
|
|
150
167
|
def configuration_file=(value)
|
|
151
168
|
value = nil if value == false
|
|
@@ -513,6 +530,22 @@ module UltraSettings
|
|
|
513
530
|
end
|
|
514
531
|
end
|
|
515
532
|
|
|
533
|
+
# Returns an array of the available data sources for the field.
|
|
534
|
+
#
|
|
535
|
+
# @param name [String, Symbol] the name of the field.
|
|
536
|
+
# @return [Array<Symbol>] The available sources (:env, :settings, :yaml, :default).
|
|
537
|
+
def __available_sources__(name)
|
|
538
|
+
field = self.class.send(:defined_fields)[name.to_s]
|
|
539
|
+
raise ArgumentError.new("Unknown field: #{name.inspect}") unless field
|
|
540
|
+
|
|
541
|
+
sources = []
|
|
542
|
+
sources << :env if field.env_var
|
|
543
|
+
sources << :settings if field.runtime_setting && UltraSettings.__runtime_settings__
|
|
544
|
+
sources << :yaml if field.yaml_key && self.class.configuration_file
|
|
545
|
+
sources << :default unless field.default.nil?
|
|
546
|
+
sources
|
|
547
|
+
end
|
|
548
|
+
|
|
516
549
|
# Output the current state of the configuration as a hash. If the field is marked as a secret,
|
|
517
550
|
# then the value will be a secure hash of the value instead of the value itself.
|
|
518
551
|
#
|
|
@@ -11,6 +11,8 @@ module UltraSettings
|
|
|
11
11
|
# <h1>Service Configuration</h1>
|
|
12
12
|
# <%= UltraSettings::ConfigurationView.new(ServiceConfiguration.instance).render %>
|
|
13
13
|
class ConfigurationView
|
|
14
|
+
include RenderHelper
|
|
15
|
+
|
|
14
16
|
# Initialize the configuration view with a configuration instance.
|
|
15
17
|
#
|
|
16
18
|
# @param configuration [UltraSettings::Configuration] The configuration instance to display.
|
|
@@ -38,10 +40,6 @@ module UltraSettings
|
|
|
38
40
|
|
|
39
41
|
private
|
|
40
42
|
|
|
41
|
-
def html_escape(value)
|
|
42
|
-
ERB::Util.html_escape(value)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
43
|
def display_value(value)
|
|
46
44
|
case value
|
|
47
45
|
when Time
|
|
@@ -147,8 +145,6 @@ module UltraSettings
|
|
|
147
145
|
HTML
|
|
148
146
|
end
|
|
149
147
|
|
|
150
|
-
private
|
|
151
|
-
|
|
152
148
|
def open_dialog_script
|
|
153
149
|
<<~JAVASCRIPT.gsub(/\s+/, " ").tr('"', "'")
|
|
154
150
|
this.closest('.ultra-settings-configuration').querySelector('.ultra-settings-dialog-title').textContent = this.dataset.label;
|
data/lib/ultra_settings/field.rb
CHANGED
|
@@ -16,12 +16,12 @@ module UltraSettings
|
|
|
16
16
|
# @param type [Symbol] The type of the field.
|
|
17
17
|
# @param description [String] The description of the field.
|
|
18
18
|
# @param default [Object] The default value of the field.
|
|
19
|
-
# @param default_if [Proc] A proc that returns true if the default value should be used.
|
|
19
|
+
# @param default_if [Proc, Symbol] A proc that returns true if the default value should be used.
|
|
20
20
|
# @param env_var [String, Symbol] The name of the environment variable to use for the field.
|
|
21
21
|
# @param runtime_setting [String, Symbol] The name of the setting to use for the field.
|
|
22
22
|
# @param yaml_key [String, Symbol] The name of the YAML key to use for the field.
|
|
23
23
|
# @param static [Boolean] Whether or not the field is static and cannot be changed at runtime.
|
|
24
|
-
# @param secret [Boolean] Whether or not the field contains a value that should be kept secret.
|
|
24
|
+
# @param secret [Boolean, Proc] Whether or not the field contains a value that should be kept secret.
|
|
25
25
|
def initialize(
|
|
26
26
|
name:,
|
|
27
27
|
type: :string,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UltraSettings
|
|
4
|
+
# Helper methods for rendering views.
|
|
5
|
+
module RenderHelper
|
|
6
|
+
# HTML escape a value.
|
|
7
|
+
#
|
|
8
|
+
# @param value [String] The value to escape.
|
|
9
|
+
# @return [String] The escaped value.
|
|
10
|
+
def html_escape(value)
|
|
11
|
+
ERB::Util.html_escape(value)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Render a partial template with the given locals.
|
|
15
|
+
#
|
|
16
|
+
# @param partial_name [String] The name of the partial template (without the leading underscore and file extension).
|
|
17
|
+
# @param locals [Hash] A hash of local variables to pass to the template.
|
|
18
|
+
# @return [String] The rendered HTML of the partial.
|
|
19
|
+
def render_partial(partial_name, locals = {})
|
|
20
|
+
template = ViewHelper.erb_template("_#{partial_name}.html.erb")
|
|
21
|
+
b = binding
|
|
22
|
+
locals.each do |key, value|
|
|
23
|
+
b.local_variable_set(key, value)
|
|
24
|
+
end
|
|
25
|
+
template.result(b)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -11,6 +11,7 @@ module UltraSettings
|
|
|
11
11
|
# @param path [String] The path to the template file.
|
|
12
12
|
# @return [ERB] The compiled ERB template.
|
|
13
13
|
def erb_template(path)
|
|
14
|
+
@cache.clear if development_mode?
|
|
14
15
|
@cache["erb:#{path}"] ||= ERB.new(read_app_file(path))
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -19,6 +20,7 @@ module UltraSettings
|
|
|
19
20
|
# @param path [String] The path to the file relative to the app directory.
|
|
20
21
|
# @return [String] The contents of the file.
|
|
21
22
|
def read_app_file(path)
|
|
23
|
+
@cache.clear if development_mode?
|
|
22
24
|
@cache["file:#{path}"] ||= File.read(File.join(app_dir, path))
|
|
23
25
|
end
|
|
24
26
|
|
|
@@ -28,6 +30,12 @@ module UltraSettings
|
|
|
28
30
|
def app_dir
|
|
29
31
|
File.expand_path(File.join("..", "..", "app"), __dir__)
|
|
30
32
|
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def development_mode?
|
|
37
|
+
ENV.fetch("RACK_ENV", "development") == "development"
|
|
38
|
+
end
|
|
31
39
|
end
|
|
32
40
|
end
|
|
33
41
|
end
|
data/lib/ultra_settings.rb
CHANGED
|
@@ -14,6 +14,7 @@ require_relative "ultra_settings/config_helper"
|
|
|
14
14
|
require_relative "ultra_settings/field"
|
|
15
15
|
require_relative "ultra_settings/rack_app"
|
|
16
16
|
require_relative "ultra_settings/view_helper"
|
|
17
|
+
require_relative "ultra_settings/render_helper"
|
|
17
18
|
require_relative "ultra_settings/web_view"
|
|
18
19
|
require_relative "ultra_settings/application_view"
|
|
19
20
|
require_relative "ultra_settings/configuration_view"
|
|
@@ -259,6 +260,19 @@ module UltraSettings
|
|
|
259
260
|
@configurations.keys
|
|
260
261
|
end
|
|
261
262
|
|
|
263
|
+
# Get an array of all of the configuration instances that have been loaded into memory.
|
|
264
|
+
#
|
|
265
|
+
# @return [Array<UltraSettings::Configuration>] The configuration instances.
|
|
266
|
+
# @api private
|
|
267
|
+
def __configurations__
|
|
268
|
+
@configurations.each do |name, class_name|
|
|
269
|
+
__load_config__(name, class_name)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
config_classes = ObjectSpace.each_object(Class).select { |klass| klass < Configuration }
|
|
273
|
+
config_classes.collect(&:instance)
|
|
274
|
+
end
|
|
275
|
+
|
|
262
276
|
private
|
|
263
277
|
|
|
264
278
|
# Load a configuration class.
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ultra_settings
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Durand
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: bundler
|
|
@@ -24,7 +23,6 @@ dependencies:
|
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: '0'
|
|
27
|
-
description:
|
|
28
26
|
email:
|
|
29
27
|
- bbdurand@gmail.com
|
|
30
28
|
executables: []
|
|
@@ -36,6 +34,9 @@ files:
|
|
|
36
34
|
- MIT-LICENSE.txt
|
|
37
35
|
- README.md
|
|
38
36
|
- VERSION
|
|
37
|
+
- app/_config_description.html.erb
|
|
38
|
+
- app/_config_list.html.erb
|
|
39
|
+
- app/_select_menu.html.erb
|
|
39
40
|
- app/application.css
|
|
40
41
|
- app/application.js
|
|
41
42
|
- app/application_vars.css.erb
|
|
@@ -53,6 +54,7 @@ files:
|
|
|
53
54
|
- lib/ultra_settings/field.rb
|
|
54
55
|
- lib/ultra_settings/rack_app.rb
|
|
55
56
|
- lib/ultra_settings/railtie.rb
|
|
57
|
+
- lib/ultra_settings/render_helper.rb
|
|
56
58
|
- lib/ultra_settings/uninitialized_runtime_settings.rb
|
|
57
59
|
- lib/ultra_settings/version.rb
|
|
58
60
|
- lib/ultra_settings/view_helper.rb
|
|
@@ -66,7 +68,6 @@ metadata:
|
|
|
66
68
|
homepage_uri: https://github.com/bdurand/ultra_settings
|
|
67
69
|
source_code_uri: https://github.com/bdurand/ultra_settings
|
|
68
70
|
changelog_uri: https://github.com/bdurand/ultra_settings/blob/main/CHANGELOG.md
|
|
69
|
-
post_install_message:
|
|
70
71
|
rdoc_options: []
|
|
71
72
|
require_paths:
|
|
72
73
|
- lib
|
|
@@ -81,8 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
81
82
|
- !ruby/object:Gem::Version
|
|
82
83
|
version: '0'
|
|
83
84
|
requirements: []
|
|
84
|
-
rubygems_version: 3.
|
|
85
|
-
signing_key:
|
|
85
|
+
rubygems_version: 3.6.9
|
|
86
86
|
specification_version: 4
|
|
87
87
|
summary: UltraSettings is a Ruby gem that provides a flexible and documented approach
|
|
88
88
|
to managing application configurations from multiple sources, including environment
|