ultra_settings 2.8.0 → 2.9.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -1
  3. data/MIT-LICENSE.txt +1 -1
  4. data/README.md +108 -1
  5. data/VERSION +1 -1
  6. data/app/AGENTS.md +7 -0
  7. data/app/_config_description.html.erb +22 -25
  8. data/app/_config_list.html.erb +2 -14
  9. data/app/_data_source.html.erb +53 -0
  10. data/app/application.css +1078 -259
  11. data/app/application.js +818 -91
  12. data/app/application_vars.css.erb +136 -81
  13. data/app/configuration.html.erb +60 -107
  14. data/app/index.html.erb +164 -20
  15. data/app/layout.css +81 -16
  16. data/app/layout.html.erb +67 -5
  17. data/app/layout_vars.css.erb +29 -5
  18. data/app/locales/ar.json +71 -0
  19. data/app/locales/cs.json +71 -0
  20. data/app/locales/da.json +71 -0
  21. data/app/locales/de.json +71 -0
  22. data/app/locales/el.json +71 -0
  23. data/app/locales/en.json +85 -0
  24. data/app/locales/es.json +71 -0
  25. data/app/locales/fa.json +71 -0
  26. data/app/locales/fr.json +71 -0
  27. data/app/locales/gd.json +71 -0
  28. data/app/locales/he.json +71 -0
  29. data/app/locales/hi.json +71 -0
  30. data/app/locales/it.json +71 -0
  31. data/app/locales/ja.json +71 -0
  32. data/app/locales/ko.json +71 -0
  33. data/app/locales/lt.json +71 -0
  34. data/app/locales/nb.json +71 -0
  35. data/app/locales/nl.json +71 -0
  36. data/app/locales/pl.json +71 -0
  37. data/app/locales/pt-br.json +71 -0
  38. data/app/locales/pt.json +71 -0
  39. data/app/locales/ru.json +71 -0
  40. data/app/locales/sv.json +71 -0
  41. data/app/locales/ta.json +71 -0
  42. data/app/locales/tr.json +71 -0
  43. data/app/locales/uk.json +71 -0
  44. data/app/locales/ur.json +71 -0
  45. data/app/locales/vi.json +71 -0
  46. data/app/locales/zh-cn.json +71 -0
  47. data/app/locales/zh-tw.json +71 -0
  48. data/lib/ultra_settings/application_view.rb +21 -3
  49. data/lib/ultra_settings/audit_data_sources.rb +98 -0
  50. data/lib/ultra_settings/coerce.rb +0 -6
  51. data/lib/ultra_settings/config_helper.rb +4 -4
  52. data/lib/ultra_settings/configuration.rb +28 -7
  53. data/lib/ultra_settings/configuration_view.rb +117 -56
  54. data/lib/ultra_settings/mini_i18n.rb +110 -0
  55. data/lib/ultra_settings/rack_app.rb +51 -1
  56. data/lib/ultra_settings/railtie.rb +8 -0
  57. data/lib/ultra_settings/tasks/audit_data_sources.rake +76 -0
  58. data/lib/ultra_settings/tasks/utils.rb +23 -0
  59. data/lib/ultra_settings/version.rb +1 -1
  60. data/lib/ultra_settings/web_view.rb +33 -2
  61. data/lib/ultra_settings.rb +56 -22
  62. data/ultra_settings.gemspec +3 -0
  63. metadata +38 -3
  64. data/app/_select_menu.html.erb +0 -53
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :ultra_settings do
4
+ desc <<~DOC
5
+ Generates a report of environment variables used in configurations that are set to their default values.
6
+ This report can help identify environment variables that are superfluous and can be removed. It skips any
7
+ environment variables that are used for secrets.
8
+ DOC
9
+ task unnecessary_env_vars: :environment do
10
+ require_relative "utils"
11
+ require_relative "../audit_data_sources"
12
+
13
+ UltraSettings::Tasks::Utils.eager_load!
14
+ env_vars_at_default = UltraSettings::AuditDataSources.unnecessary_env_vars
15
+
16
+ output = env_vars_at_default.collect do |env_var, value|
17
+ "Environment variable #{env_var} is set to its default value: #{value.inspect}"
18
+ end
19
+ puts output
20
+ end
21
+
22
+ desc <<~DOC
23
+ Generates a report of runtime settings used in configurations that are set to their default values.
24
+ This report can help identify runtime settings that are superfluous and can be removed. It skips any
25
+ runtime settings that are used for secrets.
26
+ DOC
27
+ task unnecessary_runtime_settings: :environment do
28
+ require_relative "utils"
29
+ require_relative "../audit_data_sources"
30
+
31
+ UltraSettings::Tasks::Utils.eager_load!
32
+ unnecessary_runtime_settings = UltraSettings::AuditDataSources.unnecessary_runtime_settings
33
+
34
+ output = unnecessary_runtime_settings.collect do |runtime_setting, value|
35
+ "Runtime setting #{runtime_setting} is set to its default value: #{value.inspect}"
36
+ end
37
+ puts output
38
+ end
39
+
40
+ desc <<~DOC
41
+ Generates a report of environment variables used in configurations that can be converted to runtime settings.
42
+ This report can help identify environment variables that can be removed if the corresponding runtime settings
43
+ are set. It skips any environment variables that are used for secrets.
44
+ DOC
45
+ task env_vars_can_be_runtime_setting: :environment do
46
+ require_relative "utils"
47
+ require_relative "../audit_data_sources"
48
+
49
+ UltraSettings::Tasks::Utils.eager_load!
50
+ env_vars_can_be_runtime = UltraSettings::AuditDataSources.env_vars_can_be_runtime_setting
51
+
52
+ output = env_vars_can_be_runtime.collect do |env_var, runtime_setting, value|
53
+ "Environment variable #{env_var} can be converted to runtime setting #{runtime_setting} with value: #{value.inspect}"
54
+ end
55
+ puts output
56
+ end
57
+
58
+ desc <<~DOC
59
+ Generates a report of environment variables used in configurations that do not have a default value.
60
+ This report can help identify settings that could be set in YAML or with a default value rather than via
61
+ environment variables. If these changes are made, then the environment variables could be removed.
62
+ It skips any environment variables that are used for secrets.
63
+ DOC
64
+ task env_vars_without_default: :environment do
65
+ require_relative "utils"
66
+ require_relative "../audit_data_sources"
67
+
68
+ UltraSettings::Tasks::Utils.eager_load!
69
+ env_vars_without_default = UltraSettings::AuditDataSources.env_vars_without_default
70
+
71
+ output = env_vars_without_default.collect do |config, field, env_var, value|
72
+ "Environment variable #{env_var} used by #{config}##{field} does not have a default value (current value: #{value.inspect})"
73
+ end
74
+ puts output
75
+ end
76
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UltraSettings
4
+ module Tasks
5
+ module Utils
6
+ class << self
7
+ # Helper for eager loading a Rails application.
8
+ def eager_load!
9
+ return unless defined?(Rails.application.config.eager_load)
10
+ return if Rails.application.config.eager_load
11
+
12
+ if defined?(Rails.application.eager_load!)
13
+ Rails.application.eager_load!
14
+ elsif defined?(Rails.autoloaders.zeitwerk_enabled?) && Rails.autoloaders.zeitwerk_enabled?
15
+ Rails.autoloaders.each(&:eager_load)
16
+ else
17
+ raise "Failed to eager load application."
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UltraSettings
4
- VERSION = File.read(File.join(__dir__, "..", "..", "VERSION")).strip
4
+ VERSION = File.read(File.expand_path("../../VERSION", __dir__)).strip.freeze
5
5
  end
@@ -3,6 +3,8 @@
3
3
  module UltraSettings
4
4
  # Helper class for rendering the settings information in an HTML page.
5
5
  class WebView
6
+ include RenderHelper
7
+
6
8
  attr_reader :layout_css
7
9
 
8
10
  # Initialize a new WebView with the specified color scheme.
@@ -17,8 +19,13 @@ module UltraSettings
17
19
 
18
20
  # Render the complete settings page HTML.
19
21
  #
22
+ # @param request [Rack::Request, nil] The current Rack request for access control.
23
+ # @param locale [String] The locale code for translations.
20
24
  # @return [String] The rendered HTML page.
21
- def render_settings
25
+ def render_settings(request = nil, locale: UltraSettings::MiniI18n::DEFAULT_LOCALE)
26
+ @request = request
27
+ @locale = locale
28
+ refresh_super_settings!
22
29
  @layout_template.result(binding)
23
30
  end
24
31
 
@@ -26,7 +33,25 @@ module UltraSettings
26
33
  #
27
34
  # @return [String] The HTML content for the settings.
28
35
  def content
29
- UltraSettings::ApplicationView.new(color_scheme: @color_scheme).render
36
+ UltraSettings::ApplicationView.new(
37
+ color_scheme: @color_scheme,
38
+ locale: @locale || UltraSettings::MiniI18n::DEFAULT_LOCALE
39
+ ).render
40
+ end
41
+
42
+ # Look up a translation key for the current locale.
43
+ #
44
+ # @param key [String] dotted translation key
45
+ # @return [String]
46
+ def t(key)
47
+ UltraSettings::MiniI18n.t(key, locale: @locale || UltraSettings::MiniI18n::DEFAULT_LOCALE)
48
+ end
49
+
50
+ # Return the text direction (+"ltr"+ or +"rtl"+) for the current locale.
51
+ #
52
+ # @return [String]
53
+ def text_direction
54
+ UltraSettings::MiniI18n.text_direction(@locale || UltraSettings::MiniI18n::DEFAULT_LOCALE)
30
55
  end
31
56
 
32
57
  private
@@ -36,5 +61,11 @@ module UltraSettings
36
61
  css = ViewHelper.read_app_file("layout.css")
37
62
  "#{vars}\n#{css}"
38
63
  end
64
+
65
+ def refresh_super_settings!
66
+ return unless defined?(SuperSettings) && UltraSettings.__runtime_settings__ == SuperSettings
67
+
68
+ SuperSettings.refresh_settings
69
+ end
39
70
  end
40
71
  end
@@ -8,24 +8,6 @@ require "singleton"
8
8
  require "digest"
9
9
  require "uri"
10
10
 
11
- require_relative "ultra_settings/configuration"
12
- require_relative "ultra_settings/coerce"
13
- require_relative "ultra_settings/config_helper"
14
- require_relative "ultra_settings/field"
15
- require_relative "ultra_settings/rack_app"
16
- require_relative "ultra_settings/view_helper"
17
- require_relative "ultra_settings/render_helper"
18
- require_relative "ultra_settings/web_view"
19
- require_relative "ultra_settings/application_view"
20
- require_relative "ultra_settings/configuration_view"
21
- require_relative "ultra_settings/uninitialized_runtime_settings"
22
- require_relative "ultra_settings/yaml_config"
23
- require_relative "ultra_settings/version"
24
-
25
- if defined?(Rails::Railtie)
26
- require_relative "ultra_settings/railtie"
27
- end
28
-
29
11
  # This is the root namespace for UltraSettings. You can add configurations to
30
12
  # this namespace using the add method.
31
13
  #
@@ -33,13 +15,29 @@ end
33
15
  # UltraSettings.add(:test)
34
16
  # UltraSettings.test # => TestConfiguration.instance
35
17
  module UltraSettings
36
- VALID_NAME__PATTERN = /\A[a-z_][a-zA-Z0-9_]*\z/
18
+ autoload :Configuration, File.join(__dir__, "ultra_settings/configuration")
19
+ autoload :Coerce, File.join(__dir__, "ultra_settings/coerce")
20
+ autoload :ConfigHelper, File.join(__dir__, "ultra_settings/config_helper")
21
+ autoload :Field, File.join(__dir__, "ultra_settings/field")
22
+ autoload :MiniI18n, File.join(__dir__, "ultra_settings/mini_i18n")
23
+ autoload :RackApp, File.join(__dir__, "ultra_settings/rack_app")
24
+ autoload :ViewHelper, File.join(__dir__, "ultra_settings/view_helper")
25
+ autoload :RenderHelper, File.join(__dir__, "ultra_settings/render_helper")
26
+ autoload :WebView, File.join(__dir__, "ultra_settings/web_view")
27
+ autoload :ApplicationView, File.join(__dir__, "ultra_settings/application_view")
28
+ autoload :ConfigurationView, File.join(__dir__, "ultra_settings/configuration_view")
29
+ autoload :UninitializedRuntimeSettings, File.join(__dir__, "ultra_settings/uninitialized_runtime_settings")
30
+ autoload :YamlConfig, File.join(__dir__, "ultra_settings/yaml_config")
31
+ autoload :VERSION, File.join(__dir__, "ultra_settings/version")
32
+
33
+ VALID_NAME_PATTERN = /\A[a-z_][a-zA-Z0-9_]*\z/
37
34
 
38
35
  @configurations = {}
39
36
  @mutex = Mutex.new
40
37
  @runtime_settings = nil
41
38
  @runtime_settings_url = nil
42
39
  @runtime_settings_secure = true
40
+ @super_settings_api_path = nil
43
41
 
44
42
  class << self
45
43
  # Adds a configuration to the root namespace. The configuration will be
@@ -52,7 +50,7 @@ module UltraSettings
52
50
  # @return [void]
53
51
  def add(name, klass = nil)
54
52
  name = name.to_s
55
- unless name.match?(VALID_NAME__PATTERN)
53
+ unless name.match?(VALID_NAME_PATTERN)
56
54
  raise ArgumentError.new("Invalid configuration name: #{name.inspect}")
57
55
  end
58
56
 
@@ -219,6 +217,38 @@ module UltraSettings
219
217
  @runtime_settings_secure
220
218
  end
221
219
 
220
+ # Set the URL path where the SuperSettings API is mounted. When this is set,
221
+ # the web UI will check the SuperSettings API at this path for edit access
222
+ # and load the SuperSettings api.js client library to enable inline editing
223
+ # of runtime settings.
224
+ #
225
+ # The path must be a relative URL path starting with "/". Authorization is
226
+ # handled entirely by SuperSettings — the browser makes a GET request to
227
+ # the /authorized endpoint to check access and all API calls go directly
228
+ # to the SuperSettings endpoint.
229
+ #
230
+ # @param value [String, nil] The relative URL path where SuperSettings is mounted.
231
+ # @return [void]
232
+ def super_settings_api_path=(value)
233
+ raise "super_settings gem is required for super_settings_api_path" unless defined?(::SuperSettings)
234
+
235
+ if value.nil?
236
+ @super_settings_api_path = nil
237
+ return
238
+ end
239
+
240
+ value = value.to_s
241
+ raise ArgumentError, "super_settings_api_path must be a relative URL path starting with '/'" unless value.start_with?("/")
242
+
243
+ @super_settings_api_path = value.chomp("/")
244
+ self.runtime_settings = ::SuperSettings
245
+ end
246
+
247
+ # Get the URL path where the SuperSettings API is mounted.
248
+ #
249
+ # @return [String, nil]
250
+ attr_reader :super_settings_api_path
251
+
222
252
  # Set whether fields should be considered secret by default.
223
253
  #
224
254
  # @param value [Boolean] Whether fields should be secret by default.
@@ -304,14 +334,18 @@ module UltraSettings
304
334
  if name.respond_to?(:classify)
305
335
  name.classify
306
336
  else
307
- name.split("_").map(&:capitalize).join.gsub("/", "::")
337
+ name.to_s.split("_").map(&:capitalize).join.gsub("/", "::")
308
338
  end
309
339
  end
310
340
 
311
341
  def constantize(class_name)
312
- class_name.split("::").reduce(Object) do |mod, name|
342
+ class_name.to_s.split("::").reduce(Object) do |mod, name|
313
343
  mod.const_get(name)
314
344
  end
315
345
  end
316
346
  end
317
347
  end
348
+
349
+ if defined?(Rails::Railtie)
350
+ require_relative "ultra_settings/railtie"
351
+ end
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
20
  ignore_files = %w[
21
21
  .
22
+ AGENTS.md
22
23
  Appraisals
23
24
  Gemfile
24
25
  Gemfile.lock
@@ -28,6 +29,8 @@ Gem::Specification.new do |spec|
28
29
  bin/
29
30
  gemfiles/
30
31
  spec/
32
+ test_app/
33
+ yard_plugin/
31
34
  ]
32
35
  spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
33
36
  `git ls-files -z`.split("\x0").reject { |f| ignore_files.any? { |path| f.start_with?(path) } }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ultra_settings
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand
@@ -34,9 +34,10 @@ files:
34
34
  - MIT-LICENSE.txt
35
35
  - README.md
36
36
  - VERSION
37
+ - app/AGENTS.md
37
38
  - app/_config_description.html.erb
38
39
  - app/_config_list.html.erb
39
- - app/_select_menu.html.erb
40
+ - app/_data_source.html.erb
40
41
  - app/application.css
41
42
  - app/application.js
42
43
  - app/application_vars.css.erb
@@ -45,16 +46,50 @@ files:
45
46
  - app/layout.css
46
47
  - app/layout.html.erb
47
48
  - app/layout_vars.css.erb
49
+ - app/locales/ar.json
50
+ - app/locales/cs.json
51
+ - app/locales/da.json
52
+ - app/locales/de.json
53
+ - app/locales/el.json
54
+ - app/locales/en.json
55
+ - app/locales/es.json
56
+ - app/locales/fa.json
57
+ - app/locales/fr.json
58
+ - app/locales/gd.json
59
+ - app/locales/he.json
60
+ - app/locales/hi.json
61
+ - app/locales/it.json
62
+ - app/locales/ja.json
63
+ - app/locales/ko.json
64
+ - app/locales/lt.json
65
+ - app/locales/nb.json
66
+ - app/locales/nl.json
67
+ - app/locales/pl.json
68
+ - app/locales/pt-br.json
69
+ - app/locales/pt.json
70
+ - app/locales/ru.json
71
+ - app/locales/sv.json
72
+ - app/locales/ta.json
73
+ - app/locales/tr.json
74
+ - app/locales/uk.json
75
+ - app/locales/ur.json
76
+ - app/locales/vi.json
77
+ - app/locales/zh-cn.json
78
+ - app/locales/zh-tw.json
48
79
  - lib/ultra_settings.rb
49
80
  - lib/ultra_settings/application_view.rb
81
+ - lib/ultra_settings/audit_data_sources.rb
50
82
  - lib/ultra_settings/coerce.rb
51
83
  - lib/ultra_settings/config_helper.rb
52
84
  - lib/ultra_settings/configuration.rb
53
85
  - lib/ultra_settings/configuration_view.rb
54
86
  - lib/ultra_settings/field.rb
87
+ - lib/ultra_settings/mini_i18n.rb
55
88
  - lib/ultra_settings/rack_app.rb
56
89
  - lib/ultra_settings/railtie.rb
57
90
  - lib/ultra_settings/render_helper.rb
91
+ - lib/ultra_settings/tasks/audit_data_sources.rake
92
+ - lib/ultra_settings/tasks/utils.rb
58
93
  - lib/ultra_settings/uninitialized_runtime_settings.rb
59
94
  - lib/ultra_settings/version.rb
60
95
  - lib/ultra_settings/view_helper.rb
@@ -82,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
117
  - !ruby/object:Gem::Version
83
118
  version: '0'
84
119
  requirements: []
85
- rubygems_version: 3.6.9
120
+ rubygems_version: 4.0.3
86
121
  specification_version: 4
87
122
  summary: UltraSettings is a Ruby gem that provides a flexible and documented approach
88
123
  to managing application configurations from multiple sources, including environment
@@ -1,53 +0,0 @@
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>