system_settings 0.1.0.pre → 0.1.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/README.md +108 -9
- data/app/controllers/system_settings/root_controller.rb +1 -1
- data/app/models/system_settings/configurator.rb +18 -12
- data/app/models/system_settings/errors/settings_read_error.rb +6 -0
- data/app/models/system_settings/integer_list_setting.rb +1 -1
- data/app/models/system_settings/list_of_integers_validator.rb +6 -13
- data/app/models/system_settings/list_of_strings_validator.rb +36 -0
- data/app/models/system_settings/setting.rb +1 -1
- data/app/models/system_settings/string_list_setting.rb +2 -1
- data/app/models/system_settings/string_setting.rb +1 -0
- data/app/models/system_settings/type/integer_list.rb +10 -4
- data/app/models/system_settings/type/string_list.rb +2 -1
- data/config/locales/system_settings.en.yml +2 -1
- data/db/migrate/20181007125347_create_system_settings_settings.rb +1 -1
- data/frontend/build/asset-manifest.json +4 -4
- data/frontend/build/index.html +1 -1
- data/frontend/build/precache-manifest.2450e38293bed26dfe321bf03ff5acbb.js +22 -0
- data/frontend/build/service-worker.js +1 -1
- data/frontend/build/static/css/main.493112c7.chunk.css +1 -0
- data/frontend/build/static/js/2.17170219.chunk.js +1 -0
- data/frontend/build/static/js/main.dbe11b19.chunk.js +1 -0
- data/lib/system_settings/engine.rb +5 -0
- data/lib/system_settings/version.rb +1 -1
- data/lib/system_settings.rb +16 -0
- data/lib/tasks/system_settings_tasks.rake +18 -4
- metadata +17 -55
- data/frontend/build/precache-manifest.130ca067521371497dba783c23aa7e16.js +0 -22
- data/frontend/build/static/css/main.e262560e.chunk.css +0 -1
- data/frontend/build/static/js/2.83a5f4da.chunk.js +0 -1
- data/frontend/build/static/js/main.afaa2372.chunk.js +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b0d4b4f84f7a19cd6befcc89649419e39607bb9c0e48a6b201d9c4eb8f07ba0
|
4
|
+
data.tar.gz: abc9fae1214a54c4fd6f5baeaec24a3879efa4a895c413a31b7966040a7ca274
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f83ef8531ffbaf9f01c407baa8afd93848d9e1a4ff7671e0c656298f76d1e2d71449b30fa78847f8333efdf791cfb55e93e9d7b96eafafb9e27bd3e4e5fe8264
|
7
|
+
data.tar.gz: 7a9c5493d48d403de25deac639c1055cc36cbd3a6129457bdccd99b220883ac808492b3eb39f5c3029fb04e1b687307ff9a7c0a8b1bbb12bb06fd74731452db8
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# System Settings
|
2
|
+
System Settings is a Rails engine that adds settings functionality.
|
3
3
|
|
4
|
-
|
5
|
-
How to use my plugin.
|
4
|
+
Initial setting values can be loaded from file and later edited in a System Settings provided admin panel.
|
6
5
|
|
7
|
-
|
6
|
+
|
7
|
+
## Getting started
|
8
8
|
Add this line to your application's Gemfile:
|
9
9
|
|
10
10
|
```ruby
|
@@ -16,13 +16,112 @@ And then execute:
|
|
16
16
|
$ bundle
|
17
17
|
```
|
18
18
|
|
19
|
-
|
19
|
+
Copy migrations:
|
20
|
+
```bash
|
21
|
+
$ bin/rails system_settings:install:migrations
|
22
|
+
```
|
23
|
+
|
24
|
+
And then run the migrations:
|
20
25
|
```bash
|
21
|
-
$
|
26
|
+
$ bin/rails db:migrate
|
27
|
+
```
|
28
|
+
|
29
|
+
Create settings file where all settings will be defined:
|
30
|
+
```bash
|
31
|
+
$ touch config/system_settings.rb
|
32
|
+
```
|
33
|
+
|
34
|
+
Add your first setting to `config/system_settings.rb`:
|
35
|
+
```ruby
|
36
|
+
# String type values
|
37
|
+
string :default_mail_from, value: "Example Company <noreply@example.com>", description: "This email will be used for all outgoing emails"
|
38
|
+
string :date_format, value: "%Y-%m-%d"
|
39
|
+
string :default_locale, value: "en"
|
40
|
+
|
41
|
+
# Integer type values
|
42
|
+
integer :default_records_per_page, value: 25
|
43
|
+
integer :remainder_interval_in_hours, value: 48
|
44
|
+
|
45
|
+
# Array type strings and integers
|
46
|
+
string_list :admin_emails, description: "Will receive alerts"
|
47
|
+
integer_list :lucky_numbers, description: "Prime numbers are more effective", value: [2, 3, 5, 11]
|
48
|
+
```
|
49
|
+
|
50
|
+
Load values from `config/system_settings.rb` into database:
|
51
|
+
```bash
|
52
|
+
$ ./bin/rails system_settings:load
|
53
|
+
```
|
54
|
+
|
55
|
+
Add System Settings admin panel to Rails routes:
|
56
|
+
```ruby
|
57
|
+
Rails.application.routes.draw do
|
58
|
+
mount SystemSettings::Engine, at: "/system_settings"
|
59
|
+
# rest of your routes..
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
Final step. Access settings values anywhere in your code:
|
64
|
+
```ruby
|
65
|
+
SystemSettings[:date_format] # => "%Y-%m-%d"
|
66
|
+
SystemSettings[:lucky_numbers] # => [2, 3, 5, 11]
|
67
|
+
|
68
|
+
# You can change setting's value like any other Rails model.
|
69
|
+
SystemSettings::Setting.find_by(name: "default_mail_from").update({value: "No-Reply <noreply@example.com>"})
|
70
|
+
```
|
71
|
+
|
72
|
+
|
73
|
+
## Do not forget!
|
74
|
+
Before using System settings in production please protect the `/system_settings` endpoint with routing constraint. You can read more about it in [Rails Guides: Rails Routing from the Outside In](https://guides.rubyonrails.org/routing.html#advanced-constraints)
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
Rails.application.routes.draw do
|
78
|
+
mount SystemSettings::Engine, at: "/system_settings", constraints: AdminRoutingConstraint.new
|
79
|
+
# rest of your routes..
|
80
|
+
end
|
22
81
|
```
|
23
82
|
|
24
|
-
|
25
|
-
|
83
|
+
|
84
|
+
## Few more things
|
85
|
+
|
86
|
+
When you run `./bin/rails system_settings:load` task it will read `config/system_settings.rb` file and add new entries to the database. If you would like to replace all values with the ones from the file then run `./bin/rails system_settings:reset`
|
87
|
+
|
88
|
+
System Settings admin panel is precompiled at gem's build time. So it does not require any Javascript runtime and can be used with api-only Rails applications.
|
89
|
+
|
90
|
+
If you would like to store your settings somewhere else than `config/system_settings.rb` you can use ENV variable `SYSTEM_SETTINGS_PATH` to specify custom path.
|
91
|
+
|
92
|
+
## Development
|
93
|
+
|
94
|
+
Required development dependencies:
|
95
|
+
* [Node.js](https://nodejs.org/) - JavaScript runtime
|
96
|
+
* [Yarn](https://yarnpkg.com/) - package manager
|
97
|
+
|
98
|
+
Optional development tools:
|
99
|
+
* [overmind](https://github.com/DarthSim/overmind) - Process manager for Procfile-based applications and tmux
|
100
|
+
* [direnv](https://direnv.net/) - Unclutter your .profile
|
101
|
+
|
102
|
+
Required environment variables:
|
103
|
+
* `RAILS_VERSION`
|
104
|
+
* `SQLITE3_VERSION`
|
105
|
+
|
106
|
+
As System Settings gem is being developed to be compatible with multiple [Rails](https://github.com/rails/rails) versions,
|
107
|
+
you need to set `RAILS_VERSION` and `SQLITE3_VERSION` environment variables when running `bundle install` or any `./bin/rails` command.
|
108
|
+
It is recommended to set these up using [direnv](https://direnv.net/) and `.envrc` file.
|
109
|
+
|
110
|
+
|
111
|
+
Getting started with development:
|
112
|
+
1) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 bundle`
|
113
|
+
2) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails db:create db:migrate`
|
114
|
+
3) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails test`
|
115
|
+
4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails frontend:install`
|
116
|
+
4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails app:system_settings:load`
|
117
|
+
4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 overmind start`
|
118
|
+
|
119
|
+
|
120
|
+
## Build status
|
121
|
+
System Settings is being tested with Rails versions - `5.0`, `5.1`, `5.2`, `6.0`, `rails repo master branch`
|
122
|
+
|
123
|
+
[](https://dev.azure.com/kristsozols/System%20Settings/_build/latest?definitionId=1&branchName=master)
|
124
|
+
|
26
125
|
|
27
126
|
## License
|
28
127
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -3,7 +3,7 @@ require_relative "./application_controller"
|
|
3
3
|
module SystemSettings
|
4
4
|
class RootController < ApplicationController
|
5
5
|
def index
|
6
|
-
if File.
|
6
|
+
if File.exist?(SystemSettings::Engine.frontend_build_index_html_path)
|
7
7
|
render file: SystemSettings::Engine.frontend_build_index_html_path
|
8
8
|
else
|
9
9
|
render plain: "Frontend application has not been compiled", status: :not_implemented
|
@@ -1,25 +1,30 @@
|
|
1
1
|
module SystemSettings
|
2
2
|
class Configurator
|
3
|
-
|
4
3
|
class << self
|
5
4
|
def from_file(path)
|
6
|
-
|
5
|
+
path_str = path.to_s
|
6
|
+
raise SystemSettings::Errors::SettingsReadError, "#{path_str} file does not exist" unless File.exist?(path_str)
|
7
|
+
raise SystemSettings::Errors::SettingsReadError, "#{path_str} file not readable" unless File.readable?(path_str)
|
8
|
+
file_content = File.read(path_str)
|
7
9
|
new.tap do |obj|
|
8
|
-
obj.instance_eval(file_content,
|
10
|
+
obj.instance_eval(file_content, path_str, 1)
|
9
11
|
end
|
10
12
|
end
|
13
|
+
|
14
|
+
def purge
|
15
|
+
new.purge
|
16
|
+
end
|
11
17
|
end
|
12
18
|
|
13
19
|
attr_reader :items
|
14
20
|
|
15
21
|
def initialize(&block)
|
16
22
|
@items = []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
+
return unless block_given?
|
24
|
+
if block.arity == 1
|
25
|
+
yield self
|
26
|
+
else
|
27
|
+
instance_exec(&block)
|
23
28
|
end
|
24
29
|
end
|
25
30
|
|
@@ -28,7 +33,7 @@ module SystemSettings
|
|
28
33
|
end
|
29
34
|
|
30
35
|
def string_list(name, value: nil, description: nil, &blk)
|
31
|
-
add(name, SystemSettings::StringListSetting, value: value, description: description, &blk)
|
36
|
+
add(name, SystemSettings::StringListSetting, value: value || [], description: description, &blk)
|
32
37
|
end
|
33
38
|
|
34
39
|
def integer(name, value: nil, description: nil, &blk)
|
@@ -36,7 +41,7 @@ module SystemSettings
|
|
36
41
|
end
|
37
42
|
|
38
43
|
def integer_list(name, value: nil, description: nil, &blk)
|
39
|
-
add(name, SystemSettings::IntegerListSetting, value: value, description: description, &blk)
|
44
|
+
add(name, SystemSettings::IntegerListSetting, value: value || [], description: description, &blk)
|
40
45
|
end
|
41
46
|
|
42
47
|
def persist
|
@@ -51,8 +56,9 @@ module SystemSettings
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
end
|
59
|
+
true
|
54
60
|
else
|
55
|
-
|
61
|
+
warn "SystemSettings: Settings table has not been created!"
|
56
62
|
false
|
57
63
|
end
|
58
64
|
end
|
@@ -3,6 +3,6 @@ require_relative "./setting"
|
|
3
3
|
module SystemSettings
|
4
4
|
class IntegerListSetting < Setting
|
5
5
|
attribute :value, SystemSettings::Type::IntegerList.new
|
6
|
-
validates :value, list_of_integers:
|
6
|
+
validates :value, "system_settings/list_of_integers": true
|
7
7
|
end
|
8
8
|
end
|
@@ -1,31 +1,24 @@
|
|
1
1
|
module SystemSettings
|
2
2
|
class ListOfIntegersValidator < ActiveModel::EachValidator
|
3
|
-
LIST_REGEXP = /\A[+-]?\d+(?:; *[+-]?\d+)*\z
|
4
|
-
SINGLE_REGEXP = /\A[+-]?\d+\z
|
3
|
+
LIST_REGEXP = /\A[+-]?\d+(?:; *[+-]?\d+)*\z/.freeze
|
4
|
+
SINGLE_REGEXP = /\A[+-]?\d+\z/.freeze
|
5
5
|
|
6
6
|
def validate_each(record, attr_name, value)
|
7
7
|
came_from_user = :"#{attr_name}_came_from_user?"
|
8
8
|
|
9
|
-
if record.respond_to?(came_from_user) && record.public_send(came_from_user)
|
10
|
-
raw_value = record.read_attribute_before_type_cast(attr_name)
|
11
|
-
end
|
9
|
+
raw_value = record.read_attribute_before_type_cast(attr_name) if record.respond_to?(came_from_user) && record.public_send(came_from_user)
|
12
10
|
raw_value ||= value
|
13
11
|
|
14
|
-
if record_attribute_changed_in_place?(record, attr_name)
|
15
|
-
raw_value = value
|
16
|
-
end
|
12
|
+
raw_value = value if record_attribute_changed_in_place?(record, attr_name)
|
17
13
|
|
18
|
-
unless matches_list_of_integers_regexp?(raw_value)
|
19
|
-
record.errors.add(attr_name, :not_a_list_of_integers)
|
20
|
-
return
|
21
|
-
end
|
14
|
+
record.errors.add(attr_name, :not_a_list_of_integers) unless matches_list_of_integers_regexp?(raw_value)
|
22
15
|
end
|
23
16
|
|
24
17
|
private
|
25
18
|
|
26
19
|
def record_attribute_changed_in_place?(record, attr_name)
|
27
20
|
record.respond_to?(:attribute_changed_in_place?) &&
|
28
|
-
|
21
|
+
record.attribute_changed_in_place?(attr_name.to_s)
|
29
22
|
end
|
30
23
|
|
31
24
|
def matches_list_of_integers_regexp?(raw_value)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SystemSettings
|
2
|
+
class ListOfStringsValidator < ActiveModel::EachValidator
|
3
|
+
NON_WHITESPACE_REGEXP = /[^[:space:]]/.freeze
|
4
|
+
|
5
|
+
def validate_each(record, attr_name, value)
|
6
|
+
came_from_user = :"#{attr_name}_came_from_user?"
|
7
|
+
|
8
|
+
raw_value = record.read_attribute_before_type_cast(attr_name) if record.respond_to?(came_from_user) && record.public_send(came_from_user)
|
9
|
+
raw_value ||= value
|
10
|
+
|
11
|
+
raw_value = value if record_attribute_changed_in_place?(record, attr_name)
|
12
|
+
|
13
|
+
record.errors.add(attr_name, :not_a_list_of_strings) unless matches_list_of_strings_regexp?(raw_value)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def record_attribute_changed_in_place?(record, attr_name)
|
19
|
+
record.respond_to?(:attribute_changed_in_place?) &&
|
20
|
+
record.attribute_changed_in_place?(attr_name.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def matches_list_of_strings_regexp?(raw_value)
|
24
|
+
case raw_value
|
25
|
+
when String
|
26
|
+
raw_value.split(SystemSettings::Type::StringList::DELIMITER_REGEXP).all? do |value|
|
27
|
+
NON_WHITESPACE_REGEXP.match?(value)
|
28
|
+
end
|
29
|
+
when Array
|
30
|
+
raw_value.all? { |v| NON_WHITESPACE_REGEXP.match?(v.to_s) }
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -20,11 +20,17 @@ module SystemSettings
|
|
20
20
|
def cast_value(value)
|
21
21
|
case value
|
22
22
|
when Array
|
23
|
-
value.map
|
23
|
+
value.map do |v|
|
24
|
+
v.to_i
|
25
|
+
rescue StandardError
|
26
|
+
nil
|
27
|
+
end
|
24
28
|
when String
|
25
|
-
value.split(SEPARATOR).map
|
26
|
-
|
27
|
-
|
29
|
+
value.split(SEPARATOR).map do |v|
|
30
|
+
v.to_i
|
31
|
+
rescue StandardError
|
32
|
+
nil
|
33
|
+
end
|
28
34
|
end
|
29
35
|
end
|
30
36
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module SystemSettings
|
2
2
|
module Type
|
3
3
|
class StringList < ActiveModel::Type::Value
|
4
|
+
DELIMITER_REGEXP = /(?<=[^\\]);/.freeze
|
4
5
|
def type
|
5
6
|
:string_list
|
6
7
|
end
|
@@ -20,7 +21,7 @@ module SystemSettings
|
|
20
21
|
when Array
|
21
22
|
value.map { |v| String(v).strip }
|
22
23
|
when String
|
23
|
-
value.split(
|
24
|
+
value.split(DELIMITER_REGEXP).map(&:strip).map { |str| str.gsub("\\;", ";") }
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
{
|
2
2
|
"files": {
|
3
|
-
"main.css": "/system_settings/static/css/main.
|
4
|
-
"main.js": "/system_settings/static/js/main.
|
3
|
+
"main.css": "/system_settings/static/css/main.493112c7.chunk.css",
|
4
|
+
"main.js": "/system_settings/static/js/main.dbe11b19.chunk.js",
|
5
5
|
"runtime~main.js": "/system_settings/static/js/runtime~main.a09e9b82.js",
|
6
|
-
"static/js/2.
|
6
|
+
"static/js/2.17170219.chunk.js": "/system_settings/static/js/2.17170219.chunk.js",
|
7
7
|
"index.html": "/system_settings/index.html",
|
8
|
-
"precache-manifest.
|
8
|
+
"precache-manifest.2450e38293bed26dfe321bf03ff5acbb.js": "/system_settings/precache-manifest.2450e38293bed26dfe321bf03ff5acbb.js",
|
9
9
|
"service-worker.js": "/system_settings/service-worker.js"
|
10
10
|
}
|
11
11
|
}
|
data/frontend/build/index.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"><link rel="shortcut icon" href="/system_settings/favicon.ico"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><title>System Settings</title><link href="/system_settings/static/css/main.
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"><link rel="shortcut icon" href="/system_settings/favicon.ico"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><title>System Settings</title><link href="/system_settings/static/css/main.493112c7.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script src="/system_settings/static/js/runtime~main.a09e9b82.js"></script><script src="/system_settings/static/js/2.17170219.chunk.js"></script><script src="/system_settings/static/js/main.dbe11b19.chunk.js"></script></body></html>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
self.__precacheManifest = (self.__precacheManifest || []).concat([
|
2
|
+
{
|
3
|
+
"revision": "0acf133c6751acd69af511a671c2fd1e",
|
4
|
+
"url": "/system_settings/index.html"
|
5
|
+
},
|
6
|
+
{
|
7
|
+
"revision": "e07baceb8e059f51d274",
|
8
|
+
"url": "/system_settings/static/css/main.493112c7.chunk.css"
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"revision": "f336fd31562a5938e83a",
|
12
|
+
"url": "/system_settings/static/js/2.17170219.chunk.js"
|
13
|
+
},
|
14
|
+
{
|
15
|
+
"revision": "e07baceb8e059f51d274",
|
16
|
+
"url": "/system_settings/static/js/main.dbe11b19.chunk.js"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"revision": "1b52e032205e59a9e84f",
|
20
|
+
"url": "/system_settings/static/js/runtime~main.a09e9b82.js"
|
21
|
+
}
|
22
|
+
]);
|
@@ -14,7 +14,7 @@
|
|
14
14
|
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.0/workbox-sw.js");
|
15
15
|
|
16
16
|
importScripts(
|
17
|
-
"/system_settings/precache-manifest.
|
17
|
+
"/system_settings/precache-manifest.2450e38293bed26dfe321bf03ff5acbb.js"
|
18
18
|
);
|
19
19
|
|
20
20
|
self.addEventListener('message', (event) => {
|
@@ -0,0 +1 @@
|
|
1
|
+
.App_container__BLGGc{min-height:100vh;display:flex;flex-direction:column;position:relative;z-index:auto}.App_header-wrap__3DnwX{position:fixed;width:100%;background:#fff;border-bottom:1px solid #e1e1e1;z-index:1}.App_header__1o2Y8{max-width:1020px;margin:0 auto;display:flex}.App_header-name__2XXxc{font-size:1.5rem;line-height:2rem;font-weight:700;padding:.5rem 0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none}.App_header-name__2XXxc:active,.App_header-name__2XXxc:focus,.App_header-name__2XXxc:hover{text-decoration:none}.App_header-spacer__3F0KU{margin-top:calc(3rem + 1px);height:3rem}.App_content-wrap__1oPWs{flex-grow:5;box-sizing:border-box;display:flex}.App_content__3dh9P{max-width:1020px;min-width:0;margin:0 auto;display:flex;flex-grow:1;flex-direction:column}.NotFoundPage_container__35vs4{flex-grow:1;align-items:center;justify-content:center;display:flex}.ListPage_table__2qY_8{table-layout:fixed;white-space:nowrap;width:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ListPage_table__2qY_8 td:empty:after{content:"-"}.ListPage_empty-tr__2VxYl{color:#a6a6a6}.ListPage_empty-tr__2VxYl td{text-align:center}.ListPage_name__1-Gs-{width:20%;overflow:hidden;text-overflow:ellipsis}.ListPage_table__2qY_8 tbody .ListPage_description__1Sci0,.ListPage_table__2qY_8 tbody .ListPage_name__1-Gs-,.ListPage_table__2qY_8 tbody .ListPage_value__3X3Vq{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ListPage_description__1Sci0{width:50%}.ListPage_description__1Sci0,.ListPage_value__3X3Vq{overflow:hidden;text-overflow:ellipsis}.ListPage_actions__2iqTu{width:50px;text-align:right}.PageLoadError_wrap__mpF75{display:flex;align-items:flex-start;justify-content:center}.PageLoadError_container__kcD9o{display:flex;flex-direction:column;background:#ffe5e5;padding:.25rem .5rem;border-radius:4px;color:#b94343;text-align:center}.PageLoadError_error-small__14Fex{font-size:.85em}#nprogress{pointer-events:none}#nprogress .bar{background:#ffc25b;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #ffc25b,0 0 5px #ffc25b;opacity:1;-webkit-transform:rotate(3deg) translateY(-4px);transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:.9rem;right:.9rem}#nprogress .spinner-icon{width:1.2rem;height:1.2rem;box-sizing:border-box;border-color:#ffc25b transparent transparent #ffc25b;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.Value_wrap__3J_8z{white-space:nowrap}.Value_section__cgQmL{max-width:100%;margin-right:.25em}.Value_section__cgQmL:last-child{margin-right:0}.Attribute_wrap__1Zy9J{display:flex;flex-direction:column;margin-bottom:1rem}.Attribute_name__3a-cD{font-size:.8em;color:#737373;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.Attribute_value__IxZCj:empty:after{content:"-"}.ButtonBar_container__21aEr{border-top:1px dotted #f2f2f2;padding-top:1rem;margin-bottom:1rem}.ButtonBar_container__21aEr>*{margin-right:.5rem}.LabeledInput_wrap__2KAyr{position:relative;margin-bottom:1em}.LabeledInput_label__1AyjZ{font-size:.8em;color:#737373;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:block}.LabeledInput_input-and-error-wrap__2iJKd{display:flex;align-items:baseline}.LabeledInput_error__2QBpW{flex-grow:0;display:block;color:#ff3656;margin-left:1rem;white-space:nowrap}.LabeledInput_hint__rAeG8{font-size:.8em;display:block}.SettingForm_error-wrap__3SdnI{display:flex;padding:.5rem 0}.SettingForm_error-message__uQK1Y{background:#ffe5e5;padding:.25rem .5rem;border-radius:4px;color:#b94343}.SettingForm_error-small__3owRp{font-size:.85em}.ClassicSpinner_wrap__1LF2_{display:block}html{box-sizing:border-box;overflow-y:scroll;font-size:14px}*,:after,:before{box-sizing:inherit}:root,body{background:#fff}body{color:#233656;font-family:Arial,Helvetica,sans-serif;font-weight:400;font-size:1rem;line-height:1.5rem;margin:0;padding:0;min-height:100vh;position:relative;display:flex;flex-direction:column}table{border-collapse:collapse;border-spacing:0}table td,table th{text-align:left}a{color:#233656;text-decoration:none}a:hover{text-decoration:underline}a.button,button,input[type=button],input[type=submit]{display:inline-block;cursor:pointer;border:none;border-radius:3px;padding:.375rem .75rem;font-size:1rem;line-height:1.5;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap}button,input[type=button],input[type=submit]{color:#4d4d4d;background-color:#d9d9d9;-webkit-transition:background-color .1s ease-in-out;transition:background-color .1s ease-in-out;outline:none}button:focus,button:hover,input[type=button]:focus,input[type=button]:hover,input[type=submit]:focus,input[type=submit]:hover{background-color:#b8b8b8}button:active,input[type=button]:active,input[type=submit]:active{background-color:#828282}a.button{color:#4d4d4d;background-color:initial;-webkit-transition:background-color .1s ease-in-out;transition:background-color .1s ease-in-out;outline:none;text-decoration:none}a.button:focus,a.button:hover{background-color:rgba(0,0,0,.15)}a.button:active{background-color:rgba(0,0,0,.4)}a.button.primary,button.primary,input[type=button].primary,input[type=submit].primary{color:#4d4d4d;background-color:#a6a6a6;-webkit-transition:background-color .1s ease-in-out;transition:background-color .1s ease-in-out;outline:none}a.button.primary:focus,a.button.primary:hover,button.primary:focus,button.primary:hover,input[type=button].primary:focus,input[type=button].primary:hover,input[type=submit].primary:focus,input[type=submit].primary:hover{background-color:#8d8d8d}a.button.primary:active,button.primary:active,input[type=button].primary:active,input[type=submit].primary:active{background-color:#646464}input[type=text]{border:none;border-radius:3px;padding:.5em;font-size:1rem;line-height:normal;color:#4d4d4d;background-color:#e6e6e6;-webkit-transition:background-color .1s ease-in-out;transition:background-color .1s ease-in-out;outline:none;box-sizing:initial;width:auto;min-width:12ch;max-width:calc(100% - 2em);will-change:width}input[type=text]:focus{background-color:#c4c4c4}input[type=text]:active{background-color:#bfbfbf}.button-wrap{display:flex;align-items:center}.svg-wrap{display:block}code{border-radius:2px;padding:0 .2rem}.sysname,code{background:#f2f2f2}.sysname{display:inline-block;border-radius:3px;padding:0 .5em;font-family:Courier New,Courier,monospace;font-size:.75em;max-width:100%}#root{z-index:1;position:relative}
|