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
@@ -1,45 +1,73 @@
1
1
  <% unless color_scheme == :dark %>
2
2
  .ultra-settings, .ultra-settings-block {
3
- --form-control-color: #484848;
4
- --form-control-bg-color: #fff;
5
- --form-control-border-color: #e8e8e8;
6
- --code-color: #d63384;
7
-
8
- /* Card layout colors */
9
- --config-file-bg-color: #f8f8f8;
10
- --config-file-border-color: #e8e8e8;
11
- --field-bg-color: #ffffff;
12
- --field-border-color: #b8b8b8;
13
- --field-header-bg-color: #e8e8e8;
14
- --field-header-text-color: #212529;
15
- --value-bg-color: #fdfdfe;
16
- --value-text-color: #212529;
17
- --value-code-bg-color: #f8f8f8;
18
- --value-code-border-color: #e8e8e8;
19
- --type-color: #6c757d;
20
- --description-color: #4a83b5;
21
- --nil-color: #6c757d;
22
- --warning-color: #b9202f;
23
- --info-color: #6ea8fe;
24
- --disabled-color: #adb5bd;
25
-
26
- /* Source colors */
27
- --source-bg-color: #f8f9fa;
28
- --source-border-color: #e9ecef;
29
- --source-active-bg-color: #e7f3ff;
30
- --source-active-border-color: #0d6efd;
31
- --source-type-color: #666666;
32
- --source-value-color: #444444;
33
- --source-indicator-color: #0d6efd;
34
-
35
- /* Badge colors */
36
- --secret-badge-bg-color: #dc3545;
37
- --secret-badge-text-color: #ffffff;
38
- --static-badge-bg-color: #888888;
39
- --static-badge-text-color: #ffffff;
40
-
41
- /* Edit link */
42
- --edit-link-color: #0d6efd;
3
+ --font-ui: system-ui, -apple-system, sans-serif;
4
+ --font-mono: "SF Mono", Menlo, Consolas, monospace;
5
+
6
+ /* Canvas */
7
+ --bg-page: #f4f5f7;
8
+ --bg-card: #ffffff;
9
+ --bg-code: #f0f2f5;
10
+ --bg-sticky: #f4f5f7;
11
+ --bg-overlay: rgba(30, 37, 48, 0.85);
12
+
13
+ /* Borders */
14
+ --border-light: #e2e5ea;
15
+ --border-card: #dfe2e8;
16
+
17
+ /* Text */
18
+ --text-primary: #111827;
19
+ --text-secondary: #4b5563;
20
+ --text-tertiary: #9ca3af;
21
+
22
+ /* Accent — teal */
23
+ --accent: #0d9488;
24
+ --accent-light: rgba(13, 148, 136, 0.06);
25
+ --accent-lighter: rgba(13, 148, 136, 0.03);
26
+ --accent-glow: rgba(13, 148, 136, 0.12);
27
+
28
+ /* Source palette */
29
+ --src-env: #2563eb;
30
+ --src-env-bg: #eff6ff;
31
+ --src-env-border: #bfdbfe;
32
+ --src-setting: #0d9488;
33
+ --src-setting-bg: #f0fdfa;
34
+ --src-setting-border: #99f6e4;
35
+ --src-yaml: #7c3aed;
36
+ --src-yaml-bg: #f5f3ff;
37
+ --src-yaml-border: #ddd6fe;
38
+ --src-default: #6b7280;
39
+ --src-default-bg: #f3f4f6;
40
+ --src-default-border: #d1d5db;
41
+
42
+ /* Status */
43
+ --active-color: #059669;
44
+ --active-bg: rgba(5, 150, 105, 0.05);
45
+ --overridden-color: #6b7280;
46
+
47
+ /* Badges */
48
+ --badge-secret-bg: #fef2f2;
49
+ --badge-secret-text: #dc2626;
50
+ --badge-secret-border: #fecaca;
51
+ --badge-static-bg: #f0f2f5;
52
+ --badge-static-text: #4b5563;
53
+ --badge-static-border: #d1d5db;
54
+
55
+ /* Type indicators */
56
+ --type-string: #7c3aed;
57
+ --type-integer: #2563eb;
58
+ --type-float: #0891b2;
59
+ --type-boolean: #059669;
60
+ --type-datetime: #6366f1;
61
+ --type-array: #8b5cf6;
62
+ --type-symbol: #a855f7;
63
+
64
+ /* Shadows */
65
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
66
+ --shadow-lg: 0 20px 48px rgba(0,0,0,0.12);
67
+ --shadow-card: 0 1px 3px rgba(0,0,0,0.04), 0 0 0 1px rgba(0,0,0,0.03);
68
+
69
+ /* Source row divider */
70
+ --border-source-row: rgba(0,0,0,0.025);
43
71
  }
44
72
  <% end %>
45
73
 
@@ -48,47 +76,74 @@
48
76
  <% end %>
49
77
  <% if color_scheme == :system || color_scheme == :dark %>
50
78
  .ultra-settings, .ultra-settings-block {
51
- --form-control-color: #eee;
52
- --form-control-bg-color: #666;
53
- --form-control-border-color: #555;
54
- --code-color: #fd76a3;
55
- --em-color: #adb5bd;
56
-
57
- /* Card layout colors */
58
- --config-file-bg-color: #4b4b4b;
59
- --config-file-border-color: #444;
60
- --field-bg-color: #1e1e1e;
61
- --field-border-color: #444;
62
- --field-header-bg-color: #2b2b2b;
63
- --field-header-text-color: #ced4da;
64
- --value-bg-color: #252525;
65
- --value-text-color: #e9ecef;
66
- --value-code-bg-color: #2b2b2b;
67
- --value-code-border-color: #444;
68
- --type-color: #adb5bd;
69
- --description-color: #a9d9f8;
70
- --nil-color: #cdcecfff;
71
- --warning-color: #dc3545;
72
- --info-color: #6ea8fe;
73
- --disabled-color: #adb5bd;
74
-
75
- /* Source colors */
76
- --source-bg-color: #2b2b2b;
77
- --source-border-color: #444444;
78
- --source-active-bg-color: #1a3a52;
79
- --source-active-border-color: #0d6efd;
80
- --source-type-color: #adb5bd;
81
- --source-value-color: #ced4da;
82
- --source-indicator-color: #6ea8fe;
83
-
84
- /* Badge colors */
85
- --secret-badge-bg-color: #dc3545;
86
- --secret-badge-text-color: #ffffff;
87
- --static-badge-bg-color: #6c757d;
88
- --static-badge-text-color: #ffffff;
89
-
90
- /* Edit link */
91
- --edit-link-color: #a7c6f5;
79
+ --font-ui: system-ui, -apple-system, sans-serif;
80
+ --font-mono: "SF Mono", Menlo, Consolas, monospace;
81
+
82
+ /* Canvas */
83
+ --bg-page: #0f1117;
84
+ --bg-card: #1a1c26;
85
+ --bg-code: #14161e;
86
+ --bg-sticky: #0f1117;
87
+ --bg-overlay: rgba(0, 0, 0, 0.80);
88
+
89
+ /* Borders */
90
+ --border-light: #2a2d3a;
91
+ --border-card: #252836;
92
+
93
+ /* Text */
94
+ --text-primary: #e4e6f0;
95
+ --text-secondary: #9ba1b5;
96
+ --text-tertiary: #5c6178;
97
+
98
+ /* Accent — teal */
99
+ --accent: #14b8a6;
100
+ --accent-light: rgba(20, 184, 166, 0.10);
101
+ --accent-lighter: rgba(20, 184, 166, 0.05);
102
+ --accent-glow: rgba(20, 184, 166, 0.15);
103
+
104
+ /* Source palette */
105
+ --src-env: #60a5fa;
106
+ --src-env-bg: rgba(37, 99, 235, 0.12);
107
+ --src-env-border: rgba(37, 99, 235, 0.25);
108
+ --src-setting: #2dd4bf;
109
+ --src-setting-bg: rgba(13, 148, 136, 0.12);
110
+ --src-setting-border: rgba(13, 148, 136, 0.25);
111
+ --src-yaml: #a78bfa;
112
+ --src-yaml-bg: rgba(124, 58, 237, 0.12);
113
+ --src-yaml-border: rgba(124, 58, 237, 0.25);
114
+ --src-default: #9ca3af;
115
+ --src-default-bg: rgba(107, 114, 128, 0.12);
116
+ --src-default-border: rgba(107, 114, 128, 0.25);
117
+
118
+ /* Status */
119
+ --active-color: #34d399;
120
+ --active-bg: rgba(52, 211, 153, 0.08);
121
+ --overridden-color: #6b7280;
122
+
123
+ /* Badges */
124
+ --badge-secret-bg: rgba(220, 38, 38, 0.12);
125
+ --badge-secret-text: #f87171;
126
+ --badge-secret-border: rgba(220, 38, 38, 0.25);
127
+ --badge-static-bg: rgba(107, 114, 128, 0.15);
128
+ --badge-static-text: #9ca3af;
129
+ --badge-static-border: rgba(107, 114, 128, 0.25);
130
+
131
+ /* Type indicators */
132
+ --type-string: #a78bfa;
133
+ --type-integer: #60a5fa;
134
+ --type-float: #22d3ee;
135
+ --type-boolean: #34d399;
136
+ --type-datetime: #818cf8;
137
+ --type-array: #a78bfa;
138
+ --type-symbol: #c084fc;
139
+
140
+ /* Shadows */
141
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.4), 0 1px 2px rgba(0,0,0,0.3);
142
+ --shadow-lg: 0 20px 48px rgba(0,0,0,0.6);
143
+ --shadow-card: 0 1px 3px rgba(0,0,0,0.2), 0 0 0 1px rgba(255,255,255,0.04);
144
+
145
+ /* Source row divider */
146
+ --border-source-row: rgba(255,255,255,0.04);
92
147
  }
93
148
  <% end %>
94
149
  <% if color_scheme == :system %>
@@ -5,134 +5,87 @@
5
5
  <% configuration.class.fields.each do |field| %>
6
6
  <% source = configuration.__source__(field.name) %>
7
7
 
8
- <div class="ultra-settings-field">
8
+ <%
9
+ field_search_text = [field.name, field.description, field.env_var, field.runtime_setting, field.yaml_key].compact.join(" ").downcase
10
+ %>
11
+ <div class="ultra-settings-field-card" data-field-name="<%= html_escape(field.name) %>" data-field-search="<%= html_escape(field_search_text) %>">
9
12
  <div class="ultra-settings-field-header">
10
- <div class="ultra-settings-field-name">
11
- <code><%= html_escape(field.name) %></code>
13
+ <span class="ultra-settings-field-name"><%= html_escape(field.name) %></span>
12
14
 
13
- <% if field.secret? %>
14
- <span class="ultra-settings-field-badge ultra-settings-badge-secret">
15
- secret
16
- </span>
17
- <% end %>
18
-
19
- <% if field.static? %>
20
- <span class="ultra-settings-field-badge ultra-settings-badge-static">
21
- static
22
- </span>
23
- <% end %>
24
- </div>
15
+ <span class="ultra-settings-type-indicator">
16
+ <span class="ultra-settings-type-dot" data-type="<%= html_escape(field.type) %>"></span>
17
+ <span class="ultra-settings-type-label"><%= html_escape(field.type) %></span>
18
+ </span>
25
19
 
26
- <div class="ultra-settings-field-type">
27
- <%= html_escape(field.type) %>
28
- </div>
29
- </div>
20
+ <% if field.secret? %>
21
+ <span class="ultra-settings-badge ultra-settings-badge-secret">
22
+ <%= lock_icon(10) %> <%= t('field.secret') %>
23
+ </span>
24
+ <% end %>
30
25
 
31
- <div class="ultra-settings-field-value">
32
- <% if configuration[field.name].nil? %>
33
- <span class="ultra-settings-nil-value">nil</span>
34
- <% elsif field.secret? %>
35
- <code class="ultra-settings-field-data-value">
36
- <%= html_escape(secret_value(configuration[field.name])) %>
37
- </code>
38
- <% else %>
39
- <code class="ultra-settings-field-data-value">
40
- <%= html_escape(display_value(configuration[field.name])) %>
41
- </code>
26
+ <% if field.static? %>
27
+ <span class="ultra-settings-badge ultra-settings-badge-static">
28
+ <%= pin_icon(10) %> <%= t('field.static') %>
29
+ </span>
42
30
  <% end %>
31
+
32
+ <div class="ultra-settings-field-value-wrap">
33
+ <% if configuration[field.name].nil? %>
34
+ <code class="ultra-settings-field-value nil"
35
+ onclick="<%= html_escape(open_panel_script) %>"
36
+ data-name="<%= html_escape(field.name) %>"
37
+ data-value="<%= t('field.nil') %>"
38
+ data-type="<%= html_escape(field.type) %>"
39
+ data-secret="false"
40
+ title="<%= t('field.click_to_expand') %>"
41
+ tabindex="0"
42
+ role="button"><%= t('field.nil') %></code>
43
+ <% elsif field.secret? %>
44
+ <code class="ultra-settings-field-value"
45
+ onclick="<%= html_escape(open_panel_script) %>"
46
+ data-name="<%= html_escape(field.name) %>"
47
+ data-value="<%= html_escape(secret_value(configuration[field.name])) %>"
48
+ data-type="<%= html_escape(field.type) %>"
49
+ data-secret="true"
50
+ title="<%= t('field.click_to_expand') %>"
51
+ tabindex="0"
52
+ role="button"><%= html_escape(secret_value(configuration[field.name])) %></code>
53
+ <% else %>
54
+ <code class="ultra-settings-field-value"
55
+ onclick="<%= html_escape(open_panel_script) %>"
56
+ data-name="<%= html_escape(field.name) %>"
57
+ data-value="<%= html_escape(display_value(configuration[field.name])) %>"
58
+ data-type="<%= html_escape(field.type) %>"
59
+ data-secret="false"
60
+ title="<%= t('field.click_to_expand') %>"
61
+ tabindex="0"
62
+ role="button"><%= html_escape(display_value(configuration[field.name])) %></code>
63
+ <% end %>
64
+ </div>
43
65
  </div>
44
66
 
45
67
  <% unless field.description.to_s.empty? %>
46
68
  <div class="ultra-settings-field-description">
47
- <%= info_icon %>
48
-
49
- <div class="ultra-settings-description-text">
50
- <%= html_escape(field.description) %>
51
- </div>
69
+ <%= html_escape(field.description) %>
52
70
  </div>
53
71
  <% end %>
54
72
 
55
73
  <div class="ultra-settings-field-sources">
56
74
  <% sources = configuration.__available_sources__(field.name) %>
57
75
  <% if sources.include?(:env) %>
58
- <div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :env %>">
59
- <span class="ultra-settings-source-type">
60
- Environment Variable
61
- </span>
62
-
63
- <code class="ultra-settings-source-value">
64
- <%= field.env_var %>
65
- <%= show_defined_value(field.env_var, configuration.__value_from_source__(field.name, :env), field.secret?) %>
66
- </code>
67
-
68
- <% if source == :env %>
69
- <span class="ultra-settings-source-indicator">
70
- Currently active
71
- </span>
72
- <% end %>
73
- </div>
76
+ <%= render_partial "data_source", configuration: configuration, field: field, source: :env, current_source: source %>
74
77
  <% end %>
75
78
 
76
79
  <% if sources.include?(:settings) %>
77
- <div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :settings %>">
78
- <span class="ultra-settings-source-type">Runtime Setting</span>
79
-
80
- <code class="ultra-settings-source-value">
81
- <%= field.runtime_setting %>
82
- <%= show_defined_value(field.runtime_setting, configuration.__value_from_source__(field.name, :settings), field.secret?) %>
83
- </code>
84
-
85
- <% if source == :settings %>
86
- <span class="ultra-settings-source-indicator">
87
- Currently active
88
- </span>
89
- <% end %>
90
-
91
- <% edit_url = UltraSettings.runtime_settings_url(name: field.runtime_setting, type: field.type, description: field.description) %>
92
-
93
- <% if edit_url %>
94
- <a
95
- href="<%= html_escape(edit_url) %>"
96
- class="ultra-settings-edit-link"
97
- title="Edit <%= html_escape(field.runtime_setting) %>"
98
- >
99
- <%= edit_icon %>
100
- </a>
101
- <% end %>
102
- </div>
80
+ <%= render_partial "data_source", configuration: configuration, field: field, source: :settings, current_source: source, super_settings_api_path: UltraSettings.super_settings_api_path %>
103
81
  <% end %>
104
82
 
105
83
  <% if sources.include?(:yaml) %>
106
- <div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :yaml %>">
107
- <span class="ultra-settings-source-type">Configuration File</span>
108
-
109
- <code class="ultra-settings-source-value">
110
- <%= field.yaml_key %>
111
- <%= show_defined_value(field.yaml_key, configuration.__value_from_source__(field.name, :yaml), field.secret?) %>
112
- </code>
113
-
114
- <% if source == :yaml %>
115
- <span class="ultra-settings-source-indicator">
116
- Currently active
117
- </span>
118
- <% end %>
119
- </div>
84
+ <%= render_partial "data_source", configuration: configuration, field: field, source: :yaml, current_source: source %>
120
85
  <% end %>
121
86
 
122
- <% if sources.include?(:default) || source == :default %>
123
- <div class="ultra-settings-source <%= 'ultra-settings-source-active' if source == :default %>">
124
- <span class="ultra-settings-source-type">Default Value</span>
125
-
126
- <code class="ultra-settings-source-value">
127
- <%= show_defined_value("Default Value", field.default, field.secret?) %>
128
- </code>
129
-
130
- <% if source == :default %>
131
- <span class="ultra-settings-source-indicator">
132
- Currently active
133
- </span>
134
- <% end %>
135
- </div>
87
+ <% if sources.include?(:default) %>
88
+ <%= render_partial "data_source", configuration: configuration, field: field, source: :default, current_source: source %>
136
89
  <% end %>
137
90
  </div>
138
91
  </div>
@@ -147,12 +100,12 @@
147
100
  class="ultra-settings-dialog-close"
148
101
  onclick="this.closest('.ultra-settings-dialog').close();"
149
102
  >
150
- <%= close_icon %>
103
+ <%= close_icon(15) %>
151
104
  </button>
152
105
  </div>
153
106
 
154
107
  <div class="ultra-settings-dialog-body">
155
- <code class="ultra-settings-field-data-value ultra-settings-dialog-value"></code>
108
+ <code class="ultra-settings-dialog-value"></code>
156
109
  </div>
157
110
  </dialog>
158
111
  </div>
data/app/index.html.erb CHANGED
@@ -1,34 +1,178 @@
1
1
  <%= style_tag %>
2
2
 
3
- <div class="ultra-settings">
4
- <div class="ultra-settings-nav">
5
- <% configurations = UltraSettings.__configurations__.reject { |config| config.class.fields.empty? }.sort_by { |config| config.class.name.downcase } %>
6
-
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 %>
3
+ <% configurations = UltraSettings.__configurations__.reject { |config| config.class.fields.empty? }.sort_by { |config| config.class.name.downcase } %>
4
+ <% single_config = configurations.size == 1 %>
5
+
6
+ <div class="ultra-settings"<% if UltraSettings.super_settings_api_path %> data-ss-api-path="<%= html_escape(UltraSettings.super_settings_api_path) %>"<% end %><% raw_url = UltraSettings.instance_variable_get(:@runtime_settings_url).to_s %><% unless raw_url.empty? %> data-runtime-settings-url="<%= html_escape(raw_url) %>"<% end %><% if single_config %> data-single-config="section-<%= html_escape(configurations.first.class.name) %>"<% end %>>
7
+
8
+ <% unless single_config %>
9
+ <div class="ultra-settings-topbar" id="ultra-settings-topbar">
10
+ <div class="ultra-settings-search-wrap">
11
+ <svg class="ultra-settings-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
12
+ <circle cx="11" cy="11" r="8"/>
13
+ <line x1="21" y1="21" x2="16.65" y2="16.65"/>
14
+ </svg>
15
+ <input type="text" id="ultra-settings-search-input" placeholder="<%= html_escape(t('search.placeholder')) %>" autocomplete="off" aria-label="<%= t('search.filter_aria_label') %>">
16
+ <button type="button" class="ultra-settings-search-clear" id="ultra-settings-search-clear" aria-label="<%= t('search.clear_aria') %>">
17
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
18
+ </button>
19
+ </div>
20
+ </div>
21
+ <% end %>
22
+
23
+ <div class="ultra-settings-config-list" id="ultra-settings-config-list">
24
+ <% configurations.each do |config| %>
25
+ <%
26
+ config_text = [config.class.name, config.class.description]
27
+ config.class.fields.each do |field|
28
+ config_text << field.name
29
+ config_text << field.description
30
+ config_text << field.env_var
31
+ config_text << field.runtime_setting
32
+ end
33
+ search_text = config_text.compact.join(" ").downcase
34
+ %>
35
+ <div
36
+ class="ultra-settings-config-list-item"
37
+ data-config-id="section-<%= html_escape(config.class.name) %>"
38
+ data-search="<%= html_escape(search_text) %>"
39
+ role="button"
40
+ tabindex="0"
41
+ >
42
+ <div class="ultra-settings-config-list-name"><%= html_escape(config.class.name) %></div>
43
+ <% if config.class.description %>
44
+ <div class="ultra-settings-config-list-desc"><%= html_escape(config.class.description) %></div>
45
+ <% end %>
46
+ <span class="ultra-settings-config-list-count"><%= config.class.fields.size %> <%= t('config_list.fields') %></span>
47
+ </div>
13
48
  <% end %>
14
49
  </div>
15
50
 
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 %>
51
+ <div class="ultra-settings-config-detail" id="ultra-settings-config-detail">
20
52
  <% configurations.each do |configuration| %>
21
- <div
22
- class="ultra-settings-configuration"
23
- id="config-<%= html_escape(configuration.class.name) %>"
24
- style="display:none;"
53
+ <section
54
+ class="ultra-settings-config-section"
55
+ id="section-<%= html_escape(configuration.class.name) %>"
56
+ data-config-id="section-<%= html_escape(configuration.class.name) %>"
57
+ style="display:none"
25
58
  >
26
- <%= UltraSettings::ConfigurationView.new(configuration).render(table_class: table_class) %>
27
- </div>
59
+ <%= UltraSettings::ConfigurationView.new(configuration, locale: locale).render %>
60
+ </section>
28
61
  <% end %>
62
+ </div>
63
+
64
+ <!-- Detail Panel -->
65
+ <div class="ultra-settings-panel-bg" id="ultra-settings-panel-bg"></div>
66
+ <div class="ultra-settings-detail-panel" id="ultra-settings-detail-panel" role="dialog" aria-label="<%= t('detail.field_detail') %>">
67
+ <div class="ultra-settings-dp-header">
68
+ <h3 id="ultra-settings-dp-title"></h3>
69
+ <button class="ultra-settings-dp-close" id="ultra-settings-dp-close" aria-label="<%= t('detail.close_panel') %>">
70
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
71
+ </button>
72
+ </div>
73
+ <div class="ultra-settings-dp-body">
74
+ <div class="ultra-settings-dp-value" id="ultra-settings-dp-value"></div>
75
+ <div class="ultra-settings-dp-meta" id="ultra-settings-dp-meta"></div>
76
+ </div>
77
+ </div>
78
+
79
+ <% if UltraSettings.super_settings_api_path %>
80
+ <!-- SuperSettings Edit Panel (slide-out) -->
81
+ <div class="ultra-settings-ss-panel-bg" id="ultra-settings-ss-panel-bg"></div>
82
+ <div class="ultra-settings-ss-panel" id="ultra-settings-ss-panel" role="dialog" aria-label="<%= t('edit.edit_setting') %>">
83
+ <div class="ultra-settings-dp-header">
84
+ <div>
85
+ <h3 id="ultra-settings-ss-title"><%= t('edit.title') %></h3>
86
+ <a id="ultra-settings-ss-external-link" class="ultra-settings-ss-external-link" href="#" target="_blank" rel="noopener" style="display:none;"><%= t('edit.open_dashboard') %></a>
87
+ </div>
88
+ <button class="ultra-settings-dp-close" id="ultra-settings-ss-panel-close" aria-label="<%= t('edit.close_panel') %>">
89
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
90
+ </button>
91
+ </div>
92
+ <div class="ultra-settings-dp-body">
93
+ <div class="ultra-settings-ss-loading" id="ultra-settings-ss-loading">
94
+ <%= t('edit.loading') %>
95
+ </div>
96
+
97
+ <form id="ultra-settings-ss-form" class="ultra-settings-ss-form" style="display:none;" onsubmit="return false;">
98
+ <div class="ultra-settings-ss-field">
99
+ <label class="ultra-settings-ss-label"><%= t('edit.key_label') %></label>
100
+ <input type="text" id="ultra-settings-ss-key" class="ultra-settings-ss-input" readonly>
101
+ </div>
102
+
103
+ <div class="ultra-settings-ss-field">
104
+ <label class="ultra-settings-ss-label" for="ultra-settings-ss-value-type"><%= t('edit.value_type_label') %></label>
105
+ <select id="ultra-settings-ss-value-type" class="ultra-settings-ss-input">
106
+ <option value="string"><%= t('edit.type_string') %></option>
107
+ <option value="integer"><%= t('edit.type_integer') %></option>
108
+ <option value="float"><%= t('edit.type_float') %></option>
109
+ <option value="boolean"><%= t('edit.type_boolean') %></option>
110
+ <option value="datetime"><%= t('edit.type_datetime') %></option>
111
+ <option value="array"><%= t('edit.type_array') %></option>
112
+ </select>
113
+ </div>
114
+
115
+ <div class="ultra-settings-ss-field" id="ultra-settings-ss-value-field">
116
+ <label class="ultra-settings-ss-label" for="ultra-settings-ss-value"><%= t('edit.value_label') %></label>
117
+ <textarea id="ultra-settings-ss-value" class="ultra-settings-ss-input" rows="3"></textarea>
118
+ </div>
119
+
120
+ <div class="ultra-settings-ss-field" id="ultra-settings-ss-integer-field" style="display:none;">
121
+ <label class="ultra-settings-ss-label" for="ultra-settings-ss-integer-value"><%= t('edit.value_label') %></label>
122
+ <input type="number" step="1" id="ultra-settings-ss-integer-value" class="ultra-settings-ss-input" placeholder="<%= t('edit.placeholder_integer') %>">
123
+ </div>
124
+
125
+ <div class="ultra-settings-ss-field" id="ultra-settings-ss-float-field" style="display:none;">
126
+ <label class="ultra-settings-ss-label" for="ultra-settings-ss-float-value"><%= t('edit.value_label') %></label>
127
+ <input type="number" step="any" id="ultra-settings-ss-float-value" class="ultra-settings-ss-input" placeholder="<%= t('edit.placeholder_float') %>">
128
+ </div>
129
+
130
+ <div class="ultra-settings-ss-field" id="ultra-settings-ss-boolean-field" style="display:none;">
131
+ <label class="ultra-settings-ss-label"><%= t('edit.value_label') %></label>
132
+ <label class="ultra-settings-ss-checkbox-label">
133
+ <input type="checkbox" id="ultra-settings-ss-boolean-value"> <%= t('edit.enabled') %>
134
+ </label>
135
+ </div>
136
+
137
+ <div class="ultra-settings-ss-field" id="ultra-settings-ss-datetime-field" style="display:none;">
138
+ <label class="ultra-settings-ss-label"><%= t('edit.value_label') %></label>
139
+ <div class="ultra-settings-ss-datetime-row">
140
+ <input type="datetime-local" step="1" id="ultra-settings-ss-datetime-value" class="ultra-settings-ss-input" autocomplete="off">
141
+ <span class="ultra-settings-ss-tz-label" id="ultra-settings-ss-tz-label"></span>
142
+ </div>
143
+ </div>
144
+
145
+ <div class="ultra-settings-ss-field">
146
+ <label class="ultra-settings-ss-label" for="ultra-settings-ss-description"><%= t('edit.description_label') %></label>
147
+ <textarea id="ultra-settings-ss-description" class="ultra-settings-ss-input" rows="4"></textarea>
148
+ </div>
149
+
150
+ <div class="ultra-settings-ss-history-link-wrap">
151
+ <a href="#" id="ultra-settings-ss-history-link" class="ultra-settings-ss-history-link"><%= t('edit.view_history') %></a>
152
+ </div>
153
+
154
+ <div class="ultra-settings-ss-errors" id="ultra-settings-ss-errors" style="display:none;"></div>
155
+
156
+ <div class="ultra-settings-ss-actions">
157
+ <button type="button" class="ultra-settings-ss-btn ultra-settings-ss-btn-cancel" id="ultra-settings-ss-cancel"><%= t('edit.cancel') %></button>
158
+ <button type="button" class="ultra-settings-ss-btn ultra-settings-ss-btn-save" id="ultra-settings-ss-save"><%= t('edit.save') %></button>
159
+ </div>
160
+ </form>
161
+
162
+ <div id="ultra-settings-ss-history" class="ultra-settings-ss-history" style="display:none;">
163
+ <a href="#" id="ultra-settings-ss-history-back" class="ultra-settings-ss-history-link"><%= t('edit.back_to_edit') %></a>
164
+ <div id="ultra-settings-ss-history-entries"></div>
165
+ <div id="ultra-settings-ss-history-pagination" class="ultra-settings-ss-history-pagination" style="display:none;">
166
+ <button type="button" class="ultra-settings-ss-btn ultra-settings-ss-btn-cancel" id="ultra-settings-ss-history-prev" disabled><%= t('edit.history_prev') %></button>
167
+ <button type="button" class="ultra-settings-ss-btn ultra-settings-ss-btn-cancel" id="ultra-settings-ss-history-next" disabled><%= t('edit.history_next') %></button>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </div>
29
172
  <% end %>
30
173
  </div>
31
174
 
175
+ <script>window.__ultraSettingsI18n = <%= translations_json %>;window.__ultraSettingsDir = "<%= UltraSettings::MiniI18n.text_direction(locale) %>";</script>
32
176
  <script>
33
177
  <%= javascript %>
34
178
  </script>