super_settings 1.0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/README.md +110 -16
  4. data/VERSION +1 -1
  5. data/app/helpers/super_settings/settings_helper.rb +13 -3
  6. data/app/views/layouts/super_settings/settings.html.erb +1 -1
  7. data/config/routes.rb +1 -1
  8. data/db/migrate/20210414004553_create_super_settings.rb +1 -7
  9. data/lib/super_settings/application/api.js +4 -1
  10. data/lib/super_settings/application/helper.rb +56 -17
  11. data/lib/super_settings/application/images/arrow-down-short.svg +3 -0
  12. data/lib/super_settings/application/images/arrow-up-short.svg +3 -0
  13. data/lib/super_settings/application/images/info-circle.svg +4 -0
  14. data/lib/super_settings/application/images/pencil-square.svg +4 -0
  15. data/lib/super_settings/application/images/plus.svg +3 -1
  16. data/lib/super_settings/application/images/trash3.svg +3 -0
  17. data/lib/super_settings/application/images/x-circle.svg +4 -0
  18. data/lib/super_settings/application/index.html.erb +54 -37
  19. data/lib/super_settings/application/layout.html.erb +5 -2
  20. data/lib/super_settings/application/layout_styles.css +7 -151
  21. data/lib/super_settings/application/layout_vars.css.erb +21 -0
  22. data/lib/super_settings/application/scripts.js +100 -21
  23. data/lib/super_settings/application/style_vars.css.erb +62 -0
  24. data/lib/super_settings/application/styles.css +183 -14
  25. data/lib/super_settings/application.rb +18 -11
  26. data/lib/super_settings/attributes.rb +1 -8
  27. data/lib/super_settings/configuration.rb +9 -0
  28. data/lib/super_settings/controller_actions.rb +2 -2
  29. data/lib/super_settings/engine.rb +1 -1
  30. data/lib/super_settings/history_item.rb +1 -1
  31. data/lib/super_settings/http_client.rb +165 -0
  32. data/lib/super_settings/rack_application.rb +3 -3
  33. data/lib/super_settings/rest_api.rb +5 -4
  34. data/lib/super_settings/setting.rb +13 -2
  35. data/lib/super_settings/storage/active_record_storage.rb +7 -0
  36. data/lib/super_settings/storage/history_attributes.rb +31 -0
  37. data/lib/super_settings/storage/http_storage.rb +60 -184
  38. data/lib/super_settings/storage/json_storage.rb +201 -0
  39. data/lib/super_settings/storage/mongodb_storage.rb +238 -0
  40. data/lib/super_settings/storage/redis_storage.rb +49 -111
  41. data/lib/super_settings/storage/s3_storage.rb +165 -0
  42. data/lib/super_settings/storage/storage_attributes.rb +64 -0
  43. data/lib/super_settings/storage/test_storage.rb +3 -5
  44. data/lib/super_settings/storage/transaction.rb +67 -0
  45. data/lib/super_settings/storage.rb +13 -6
  46. data/lib/super_settings/time_precision.rb +36 -0
  47. data/lib/super_settings.rb +11 -0
  48. data/super_settings.gemspec +4 -2
  49. metadata +22 -9
  50. data/lib/super_settings/application/images/edit.svg +0 -1
  51. data/lib/super_settings/application/images/info.svg +0 -1
  52. data/lib/super_settings/application/images/slash.svg +0 -1
  53. data/lib/super_settings/application/images/trash.svg +0 -1
@@ -0,0 +1,62 @@
1
+ .super-settings {
2
+ --primary-color-h: 216;
3
+ --primary-color-s: 98%;
4
+ --primary-color-l: 52%;
5
+ --primary-color-hsl: var(--primary-color-h), var(--primary-color-s), var(--primary-color-l);
6
+ --primary-color: hsl(var(--primary-color-hsl));
7
+ --primary-contrast-color: #fff;
8
+ --primary-hover-color: hsl(var(--primary-color-h), var(--primary-color-s), calc(var(--primary-color-l) - 10%));
9
+ --primary-border-color: hsl(var(--primary-color-h), var(--primary-color-s), calc(var(--primary-color-l) + 10%));
10
+ }
11
+
12
+ <% unless color_scheme == :dark %>
13
+ .super-settings {
14
+ --edit-bg-color: #f2fdf2;
15
+ --deleted-row-color: darkred;
16
+ --deleted-row-bg-color: #ffd1d8;
17
+ --history-key-color: royalblue;
18
+ --table-header-bg-color: #fff;
19
+ --table-border-color: #dee2e6;
20
+ --alt-row-color: rgba(0, 0, 0, .05);
21
+ --form-control-color: #495057;
22
+ --form-control-bg-color: #fff;
23
+ --form-control-border-color: #ced4da;
24
+ --form-control-placeholder-color: #bbb;
25
+ --modal-bg-color: #fff;
26
+ --modal-transparency: 0.4;
27
+ --modal-control-color: #000;
28
+ --success-color: green;
29
+ --danger-color: firebrick;
30
+ --muted-color: #666;
31
+ --unselected-color: #666;
32
+ }
33
+ <% end %>
34
+
35
+ <% if color_scheme == :system %>
36
+ @media (prefers-color-scheme: dark) {
37
+ <% end %>
38
+ <% if color_scheme == :system || color_scheme == :dark %>
39
+ .super-settings {
40
+ --edit-bg-color: #8dc875;
41
+ --deleted-row-color: #e0b1b8;
42
+ --deleted-row-bg-color: #7a3636;
43
+ --history-key-color: #a7d6f4;
44
+ --table-header-bg-color: #333;
45
+ --table-border-color: #555;
46
+ --alt-row-color: rgba(0, 0, 0, .30);
47
+ --form-control-color: #eee;
48
+ --form-control-bg-color: #666;
49
+ --form-control-border-color: #555;
50
+ --form-control-placeholder-color: #aaa;
51
+ --modal-bg-color: #333;
52
+ --modal-transparency: 0.75;
53
+ --modal-control-color: #fff;
54
+ --success-color: #00ff00;
55
+ --danger-color: #ff0000;
56
+ --muted-color: #999;
57
+ --unselected-color: #ccc;
58
+ }
59
+ <% end %>
60
+ <% if color_scheme == :system %>
61
+ }
62
+ <% end %>
@@ -1,3 +1,10 @@
1
+ .super-settings-container {
2
+ padding-left: 15px;
3
+ padding-right: 15px;
4
+ margin-left: auto;
5
+ margin-right: auto;
6
+ }
7
+
1
8
  #settings-table td p {
2
9
  margin-top: 0;
3
10
  margin-bottom: 0.5rem;
@@ -11,13 +18,9 @@
11
18
  width: 100%;
12
19
  }
13
20
 
14
- .super-settings-edit-row {
15
- background-color: #f2fdf2 !important;
16
- }
17
-
18
21
  #settings-table tr[data-deleted] td {
19
- background-color: #ffd1d8 !important;
20
- color: darkred;
22
+ background-color: var(--deleted-row-bg-color) !important;
23
+ color: var(--deleted-row-color);
21
24
  text-decoration: line-through;
22
25
  }
23
26
 
@@ -25,16 +28,49 @@
25
28
  display: none;
26
29
  }
27
30
 
31
+ .super-settings-icon {
32
+ display: inline-block;
33
+ }
34
+
35
+ .super-settings-icon svg {
36
+ width: 100%;
37
+ height: 100%;
38
+ vertical-align: inherit;
39
+ }
40
+
41
+ .super-settings-btn-no-chrome {
42
+ display: inline-block;
43
+ vertical-align: middle;
44
+ background-color: transparent;
45
+ border: 0;
46
+ padding: 0;
47
+ cursor: pointer;
48
+ }
49
+
50
+
51
+
52
+ .super-settings-sort-control {
53
+ color: var(--unselected-color);
54
+ }
55
+
56
+ .super-settings-sort-control svg {
57
+ vertical-align: middle;
58
+ }
59
+
60
+ .super-settings-edit-row {
61
+ background-color: var(--edit-bg-color) !important;
62
+ }
63
+
28
64
  .super-settings-key {
29
65
  overflow-wrap: break-word;
30
66
  max-width: 30rem;
31
- min-width: 15rem;
67
+ min-width: 8rem;
32
68
  }
33
69
 
34
70
  .super-settings-value {
35
71
  overflow-wrap: break-word;
36
72
  max-width: 30rem;
37
- min-width: 15rem;
73
+ min-width: 8rem;
38
74
  }
39
75
 
40
76
  .super-settings-value-type {
@@ -59,7 +95,34 @@
59
95
 
60
96
  .super-settings-history-key {
61
97
  font-weight: normal;
62
- color: royalblue;
98
+ color: var(--history-key-color);
99
+ }
100
+
101
+ .super-settings-table {
102
+ width: 100%;
103
+ max-width: 100%;
104
+ margin-bottom: 1rem;
105
+ border-collapse: collapse;
106
+ }
107
+
108
+ .super-settings-table thead th {
109
+ vertical-align: bottom;
110
+ border-bottom: 2px solid var(--table-border-color);
111
+ white-space: nowrap;
112
+ }
113
+
114
+ .super-settings-table td, .super-settings-table th {
115
+ padding: 0.75rem;
116
+ vertical-align: top;
117
+ border-top: 1px solid var(--table-border-color);
118
+ }
119
+
120
+ .super-settings-table-striped tbody tr:nth-of-type(odd) {
121
+ background-color: var(--alt-row-color);
122
+ }
123
+
124
+ .super-settings-align-center {
125
+ text-align: center;
63
126
  }
64
127
 
65
128
  .super-settings-modal {
@@ -72,12 +135,12 @@
72
135
  width: 100%;
73
136
  height: 100%;
74
137
  overflow: auto;
75
- background-color: rgba(0,0,0,0.4);
138
+ background-color: rgba(0, 0, 0, var(--modal-transparency));
76
139
  }
77
140
 
78
141
  .super-settings-modal-dialog {
79
142
  margin: auto;
80
- background-color: #fff;
143
+ background-color: var(--modal-bg-color);
81
144
  position: relative;
82
145
  outline: 0;
83
146
  padding: 2em;
@@ -99,7 +162,7 @@
99
162
  right: 0;
100
163
  border: 0;
101
164
  padding: 1ex;
102
- background-color: inherit;
165
+ color: var(--modal-control-color);
103
166
  font-size: 1.5rem;
104
167
  font-weight: 500;
105
168
  }
@@ -122,6 +185,112 @@
122
185
  .super-settings-sticky-top {
123
186
  position: sticky;
124
187
  top: 0;
125
- padding: 1rem 0;
126
- background-color: white;
188
+ padding: 1rem;
189
+ background-color: var(--table-header-bg-color);
190
+ }
191
+
192
+ .super-settings-form-control {
193
+ font-family: inherit;
194
+ margin: 0;
195
+ overflow: visible;
196
+ display: block;
197
+ width: 100%;
198
+ padding: .375rem .75rem;
199
+ font-size: 1rem;
200
+ line-height: 1.5;
201
+ color: var(--form-control-color);
202
+ background-color: var(--form-control-bg-color);
203
+ background-clip: padding-box;
204
+ border: 1px solid var(--form-control-border-color);
205
+ border-radius: .25rem;
206
+ transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
207
+ }
208
+
209
+ .super-settings-form-control::placeholder {
210
+ color: var(--form-control-placeholder-color);
211
+ }
212
+
213
+ select.super-settings-form-control:not([size]):not([multiple]) {
214
+ height: calc(2.25rem + 2px);
215
+ }
216
+
217
+ .super-settings-form-check {
218
+ margin-top: .5rem;
219
+ display: inline-block;
220
+ }
221
+
222
+ .super-settings-form-check input[type=checkbox] {
223
+ vertical-align: middle;
224
+ }
225
+
226
+ .super-settings-form-inline {
227
+ display: inline-block;
228
+ }
229
+
230
+ .super-settings-form-inline .super-settings-form-control {
231
+ display: inline-block;
232
+ width: auto;
233
+ vertical-align: middle;
234
+ }
235
+
236
+ .super-settings-form-control textarea {
237
+ font-family: inherit;
238
+ margin: 0;
239
+ overflow: auto;
240
+ resize: vertical;
241
+ }
242
+
243
+ .super-settings-text-success {
244
+ color: var(--success-color) !important;
245
+ }
246
+
247
+ .super-settings-text-danger {
248
+ color: var(--danger-color) !important;
249
+ }
250
+
251
+ .super-settings-text-muted {
252
+ color: var(--muted-color) !important;
253
+ }
254
+
255
+ .super-settings-btn {
256
+ display: inline-block;
257
+ vertical-align: middle;
258
+ padding: 0.375rem 0.75rem;
259
+ border-radius: 0.375rem;
260
+ border: 1px solid #dcdcdc;
261
+ background-color:#f9f9f9;
262
+ text-decoration: none;
263
+ text-align: center;
264
+ font-family: Arial, sans-serif;
265
+ font-size: 1rem;
266
+ font-weight: 400;
267
+ line-height: 1.5;
268
+ user-select: none;
269
+ cursor: pointer;
270
+ transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out, box-shadow .15s ease-in-out;
271
+ }
272
+
273
+ .super-settings-btn:hover:not(:disabled) {
274
+ background-color:#e9e9e9;
275
+ }
276
+ .super-settings-btn:active {
277
+ position:relative;
278
+ top:1px;
279
+ }
280
+ .super-settings-btn:disabled {
281
+ opacity: 0.8;
282
+ cursor: not-allowed;
283
+ }
284
+
285
+ .super-settings-btn-primary {
286
+ background-color: var(--primary-color);
287
+ border-color: var(--primary-border-color);
288
+ color: var(--primary-contrast-color);
289
+ }
290
+ .super-settings-btn-primary:hover:not(:disabled) {
291
+ background-color: var(--primary-hover-color);
292
+ }
293
+
294
+ .super-settings-btn-primary:disabled {
295
+ opacity: 0.5;
127
296
  }
@@ -10,31 +10,38 @@ module SuperSettings
10
10
  # @param layout [String, Symbol] path to an ERB template to use as the layout around the application UI. You can
11
11
  # pass the symbol +:default+ to use the default layout that ships with the gem.
12
12
  # @param add_to_head [String] HTML code to add to the <head> element on the page.
13
- def initialize(layout = nil, add_to_head = nil)
13
+ # @param api_base_url [String] the base URL for the REST API.
14
+ # @param color_scheme [Symbol] whether to use dark mode for the application UI. If +nil+, the user's system
15
+ # preference will be used.
16
+ def initialize(layout: nil, add_to_head: nil, api_base_url: nil, color_scheme: nil)
14
17
  if layout
15
18
  layout = File.expand_path(File.join("application", "layout.html.erb"), __dir__) if layout == :default
16
- @layout = ERB.new(File.read(layout))
19
+ @layout = ERB.new(File.read(layout)) if layout
17
20
  @add_to_head = add_to_head
21
+ else
22
+ @layout = nil
23
+ @add_to_head = nil
18
24
  end
25
+
26
+ @api_base_url = api_base_url
27
+ @color_scheme = color_scheme&.to_sym
19
28
  end
20
29
 
21
- # Render the specified ERB file in the lib/application directory distributed with the gem.
30
+ # Render the web UI application HTML.
22
31
  #
23
32
  # @return [void]
24
- def render(erb_file)
25
- template = ERB.new(File.read(File.expand_path(File.join("application", erb_file), __dir__)))
33
+ def render
34
+ template = ERB.new(File.read(File.expand_path(File.join("application", "index.html.erb"), __dir__)))
26
35
  html = template.result(binding)
27
- if @layout
28
- render_layout { html }
29
- else
30
- html
31
- end
36
+ html = render_layout { html } if @layout
37
+ html = html.html_safe if html.respond_to?(:html_safe)
38
+ html
32
39
  end
33
40
 
34
41
  private
35
42
 
36
43
  def render_layout
37
- @layout.result(binding)
44
+ @layout&.result(binding)
38
45
  end
39
46
  end
40
47
  end
@@ -4,20 +4,13 @@ module SuperSettings
4
4
  # Interface to expose mass setting attributes on an object. Setting attributes with a
5
5
  # hash will simply call the attribute writers for each key in the hash.
6
6
  module Attributes
7
- class UnknownAttributeError < StandardError
8
- end
9
-
10
7
  def initialize(attributes = nil)
11
8
  self.attributes = attributes if attributes
12
9
  end
13
10
 
14
11
  def attributes=(values)
15
12
  values.each do |name, value|
16
- if respond_to?(:"#{name}=", true)
17
- send(:"#{name}=", value)
18
- else
19
- raise UnknownAttributeError.new("unknown attribute #{name.to_s.inspect} for #{self.class}")
20
- end
13
+ send(:"#{name}=", value) if respond_to?(:"#{name}=", true)
21
14
  end
22
15
  end
23
16
  end
@@ -25,6 +25,7 @@ module SuperSettings
25
25
  def initialize
26
26
  @superclass = nil
27
27
  @web_ui_enabled = true
28
+ @color_scheme = false
28
29
  @changed_by_block = nil
29
30
  end
30
31
 
@@ -63,6 +64,14 @@ module SuperSettings
63
64
  !!@web_ui_enabled
64
65
  end
65
66
 
67
+ # Set dark mode for the web UI. Possible values are :light, :dark, or :system.
68
+ # The default value is :light.
69
+ attr_writer :color_scheme
70
+
71
+ def color_scheme
72
+ (@color_scheme ||= :light).to_sym
73
+ end
74
+
66
75
  # Enhance the controller. You can define methods or call controller class methods like
67
76
  # +before_action+, etc. in the block. These will be applied to the engine controller.
68
77
  # This is essentially the same a monkeypatching the controller class.
@@ -19,7 +19,7 @@ module SuperSettings
19
19
 
20
20
  # Render the HTML application for managing settings.
21
21
  def root
22
- html = SuperSettings::Application.new.render("index.html.erb")
22
+ html = SuperSettings::Application.new.render
23
23
  render html: html.html_safe, layout: true
24
24
  end
25
25
 
@@ -40,7 +40,7 @@ module SuperSettings
40
40
 
41
41
  # API endpoint for updating settings. See SuperSettings::RestAPI for details.
42
42
  def update
43
- changed_by = Configuration.instance.controller.changed_by(self)
43
+ changed_by = SuperSettings.configuration.controller.changed_by(self)
44
44
  result = SuperSettings::RestAPI.update(params[:settings], changed_by)
45
45
  if result[:success]
46
46
  render json: result
@@ -27,7 +27,7 @@ module SuperSettings
27
27
 
28
28
  config.after_initialize do
29
29
  # Call the deferred initialization block.
30
- configuration = Configuration.instance
30
+ configuration = SuperSettings.configuration
31
31
  configuration.call
32
32
 
33
33
  SuperSettings.refresh_interval = configuration.refresh_interval unless configuration.refresh_interval.nil?
@@ -27,7 +27,7 @@ module SuperSettings
27
27
  def changed_by_display
28
28
  return changed_by if changed_by.nil?
29
29
 
30
- display_proc = Configuration.instance.model.changed_by_display
30
+ display_proc = SuperSettings.configuration.model.changed_by_display
31
31
  if display_proc && !changed_by.nil?
32
32
  display_proc.call(changed_by) || changed_by
33
33
  else
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+
6
+ module SuperSettings
7
+ # This is a simple HTTP client that is used to communicate with the REST API. It
8
+ # will keep the connection alive and reuse it on subsequent requests.
9
+ class HttpClient
10
+ DEFAULT_HEADERS = {"Accept" => "application/json"}.freeze
11
+ DEFAULT_TIMEOUT = 5.0
12
+ KEEP_ALIVE_TIMEOUT = 60
13
+
14
+ class Error < StandardError
15
+ end
16
+
17
+ class NotFoundError < Error
18
+ end
19
+
20
+ class InvalidRecordError < Error
21
+ attr_reader :errors
22
+
23
+ def initialize(message, errors:)
24
+ super(message)
25
+ @errors = errors
26
+ end
27
+ end
28
+
29
+ def initialize(base_url, headers: nil, params: nil, timeout: nil, user: nil, password: nil)
30
+ base_url = "#{base_url}/" unless base_url.end_with?("/")
31
+ @base_uri = URI(base_url)
32
+ @base_uri.query = query_string(params) if params
33
+ @headers = headers ? DEFAULT_HEADERS.merge(headers) : DEFAULT_HEADERS
34
+ @timeout = timeout || DEFAULT_TIMEOUT
35
+ @user = user
36
+ @password = password
37
+ @mutex = Mutex.new
38
+ @connections = []
39
+ end
40
+
41
+ def get(path, params = nil)
42
+ request = Net::HTTP::Get.new(request_uri(path, params))
43
+ send_request(request)
44
+ end
45
+
46
+ def post(path, params = nil)
47
+ request = Net::HTTP::Post.new(request_uri(path))
48
+ request.body = JSON.dump(params) if params
49
+ send_request(request)
50
+ end
51
+
52
+ private
53
+
54
+ def send_request(request)
55
+ set_headers(request)
56
+ response_payload = nil
57
+ attempts = 0
58
+
59
+ with_connection do |http|
60
+ http.start unless http.started?
61
+ response = http.request(request)
62
+
63
+ begin
64
+ response.value # raises exception unless response is a success
65
+ response_payload = JSON.parse(response.body)
66
+ rescue Net::ProtocolError
67
+ if [404, 410].include?(response.code.to_i)
68
+ raise NotFoundError.new("#{response.code} #{response.message}")
69
+ elsif response.code.to_i == 422
70
+ raise InvalidRecordError.new("#{response.code} #{response.message}", errors: JSON.parse(response.body)["errors"])
71
+ else
72
+ raise Error.new("#{response.code} #{response.message}")
73
+ end
74
+ rescue JSON::JSONError => e
75
+ raise Error.new(e.message)
76
+ end
77
+ rescue IOError, Errno::ECONNRESET => connection_error
78
+ attempts += 1
79
+ retry if attempts <= 1
80
+ raise connection_error
81
+ end
82
+
83
+ response_payload
84
+ end
85
+
86
+ def with_connection(&block)
87
+ http = pop_connection
88
+ begin
89
+ response = yield(http)
90
+ return_connection(http)
91
+ response
92
+ rescue => e
93
+ begin
94
+ http.finish if http.started?
95
+ rescue IOError
96
+ end
97
+ raise e
98
+ end
99
+ end
100
+
101
+ def pop_connection
102
+ http = nil
103
+ @mutex.synchronize do
104
+ http = @connections.pop
105
+ end
106
+ http = nil unless http&.started?
107
+ http ||= new_connection
108
+ http
109
+ end
110
+
111
+ def return_connection(http)
112
+ @mutex.synchronize do
113
+ if @connections.empty?
114
+ @connections.push(http)
115
+ http = nil
116
+ end
117
+ end
118
+
119
+ if http
120
+ begin
121
+ http.finish if http.started?
122
+ rescue IOError
123
+ end
124
+ end
125
+ end
126
+
127
+ def new_connection
128
+ http = Net::HTTP.new(@base_uri.host, @base_uri.port || @base_uri.inferred_port)
129
+ http.use_ssl = @base_uri.scheme == "https"
130
+ http.open_timeout = @timeout
131
+ http.read_timeout = @timeout
132
+ http.write_timeout = @timeout
133
+ http.keep_alive_timeout = KEEP_ALIVE_TIMEOUT
134
+ http
135
+ end
136
+
137
+ def set_headers(request)
138
+ @headers.each do |name, value|
139
+ name = name.to_s
140
+ values = Array(value)
141
+ request[name] = values[0].to_s
142
+ values[1, values.length].each do |val|
143
+ request.add_field(name, val.to_s)
144
+ end
145
+ end
146
+ end
147
+
148
+ def request_uri(path, params = nil)
149
+ uri = URI.join(@base_uri, path.delete_prefix("/"))
150
+ if (params && !params.empty?) || (@base_uri.query && !@base_uri.query.empty?)
151
+ uri.query = [uri.query, query_string(params)].join("&")
152
+ end
153
+ uri
154
+ end
155
+
156
+ def query_string(params)
157
+ q = []
158
+ q << @base_uri.query unless @base_uri.query.to_s.empty?
159
+ params&.each do |name, value|
160
+ q << "#{URI.encode_www_form_component(name.to_s)}=#{URI.encode_www_form_component(value.to_s)}"
161
+ end
162
+ q.join("&")
163
+ end
164
+ end
165
+ end
@@ -122,7 +122,7 @@ module SuperSettings
122
122
  #
123
123
  # @return [Boolean]
124
124
  def web_ui_enabled?
125
- true
125
+ SuperSettings.configuration.controller.web_ui_enabled?
126
126
  end
127
127
 
128
128
  private
@@ -159,7 +159,7 @@ module SuperSettings
159
159
 
160
160
  def handle_root_request(request)
161
161
  response = check_authorization(request, write_required: true) do |user|
162
- [200, {"content-type" => "text/html; charset=utf-8", "cache-control" => "no-cache"}, [Application.new(:default, add_to_head(request)).render("index.html.erb")]]
162
+ [200, {"content-type" => "text/html; charset=utf-8", "cache-control" => "no-cache"}, [Application.new(layout: :default, add_to_head: add_to_head(request), color_scheme: SuperSettings.configuration.controller.color_scheme).render]]
163
163
  end
164
164
 
165
165
  if [401, 403].include?(response.first)
@@ -236,7 +236,7 @@ module SuperSettings
236
236
 
237
237
  def post_params(request)
238
238
  if request.content_type.to_s.match?(/\Aapplication\/json/i) && request.body
239
- request.params.merge(JSON.parse(request.body.string))
239
+ request.params.merge(JSON.parse(request.body.read))
240
240
  else
241
241
  request.params
242
242
  end
@@ -23,7 +23,7 @@ module SuperSettings
23
23
  # ...
24
24
  # ]
25
25
  def index
26
- settings = Setting.active.sort_by(&:key)
26
+ settings = Setting.active.reject(&:deleted?).sort_by(&:key)
27
27
  {settings: settings.collect(&:as_json)}
28
28
  end
29
29
 
@@ -46,7 +46,8 @@ module SuperSettings
46
46
  # updated_at: iso8601 string
47
47
  # }
48
48
  def show(key)
49
- Setting.find_by_key(key)&.as_json
49
+ setting = Setting.find_by_key(key)
50
+ setting.as_json if setting && !setting.deleted?
50
51
  end
51
52
 
52
53
  # The update operation uses a transaction to atomically update all settings.
@@ -156,7 +157,7 @@ module SuperSettings
156
157
  #
157
158
  # @example
158
159
  # GET /last_updated_at
159
- # #
160
+ #
160
161
  # The response payload is:
161
162
  # {
162
163
  # last_updated_at: iso8601 string
@@ -188,7 +189,7 @@ module SuperSettings
188
189
  # ]
189
190
  def updated_since(time)
190
191
  time = Coerce.time(time)
191
- settings = Setting.updated_since(time)
192
+ settings = Setting.updated_since(time).reject(&:deleted?)
192
193
  {settings: settings.collect(&:as_json)}
193
194
  end
194
195
  end