super_settings 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +110 -16
- data/VERSION +1 -1
- data/app/helpers/super_settings/settings_helper.rb +13 -3
- data/app/views/layouts/super_settings/settings.html.erb +1 -1
- data/config/routes.rb +1 -1
- data/db/migrate/20210414004553_create_super_settings.rb +1 -7
- data/lib/super_settings/application/api.js +4 -1
- data/lib/super_settings/application/helper.rb +56 -17
- data/lib/super_settings/application/images/arrow-down-short.svg +3 -0
- data/lib/super_settings/application/images/arrow-up-short.svg +3 -0
- data/lib/super_settings/application/images/info-circle.svg +4 -0
- data/lib/super_settings/application/images/pencil-square.svg +4 -0
- data/lib/super_settings/application/images/plus.svg +3 -1
- data/lib/super_settings/application/images/trash3.svg +3 -0
- data/lib/super_settings/application/images/x-circle.svg +4 -0
- data/lib/super_settings/application/index.html.erb +54 -37
- data/lib/super_settings/application/layout.html.erb +5 -2
- data/lib/super_settings/application/layout_styles.css +7 -151
- data/lib/super_settings/application/layout_vars.css.erb +21 -0
- data/lib/super_settings/application/scripts.js +100 -21
- data/lib/super_settings/application/style_vars.css.erb +62 -0
- data/lib/super_settings/application/styles.css +183 -14
- data/lib/super_settings/application.rb +18 -11
- data/lib/super_settings/attributes.rb +1 -8
- data/lib/super_settings/configuration.rb +9 -0
- data/lib/super_settings/controller_actions.rb +2 -2
- data/lib/super_settings/engine.rb +1 -1
- data/lib/super_settings/history_item.rb +1 -1
- data/lib/super_settings/http_client.rb +165 -0
- data/lib/super_settings/rack_application.rb +3 -3
- data/lib/super_settings/rest_api.rb +5 -4
- data/lib/super_settings/setting.rb +13 -2
- data/lib/super_settings/storage/active_record_storage.rb +7 -0
- data/lib/super_settings/storage/history_attributes.rb +31 -0
- data/lib/super_settings/storage/http_storage.rb +60 -184
- data/lib/super_settings/storage/json_storage.rb +201 -0
- data/lib/super_settings/storage/mongodb_storage.rb +238 -0
- data/lib/super_settings/storage/redis_storage.rb +49 -111
- data/lib/super_settings/storage/s3_storage.rb +165 -0
- data/lib/super_settings/storage/storage_attributes.rb +64 -0
- data/lib/super_settings/storage/test_storage.rb +3 -5
- data/lib/super_settings/storage/transaction.rb +67 -0
- data/lib/super_settings/storage.rb +13 -6
- data/lib/super_settings/time_precision.rb +36 -0
- data/lib/super_settings.rb +11 -0
- data/super_settings.gemspec +4 -2
- metadata +22 -9
- data/lib/super_settings/application/images/edit.svg +0 -1
- data/lib/super_settings/application/images/info.svg +0 -1
- data/lib/super_settings/application/images/slash.svg +0 -1
- data/lib/super_settings/application/images/trash.svg +0 -1
@@ -1,33 +1,46 @@
|
|
1
1
|
<%= style_tag %>
|
2
2
|
|
3
|
-
<main>
|
4
|
-
<form class="form-inline" style="display:block;" onsubmit="return false">
|
3
|
+
<main class="super-settings" data-api-base-url="<%= html_escape(api_base_url) %>">
|
4
|
+
<form class="super-settings-form-inline" style="display:block;" onsubmit="return false">
|
5
5
|
<div class="super-settings-sticky-top">
|
6
6
|
<span class="js-settings-count" style="display:inline-block; margin-right:1rem;"></span>
|
7
7
|
|
8
|
-
<label for="filter" class="super-settings-sr-only">Filter</label>
|
9
|
-
<input type="text" name="filter" value="" placeholder="Filter Keys" size="20" class="form-control" title="Filter Keys" id="filter" style="margin-right:1rem;">
|
8
|
+
<label for="super-settings-filter" class="super-settings-sr-only">Filter</label>
|
9
|
+
<input type="text" name="filter" value="" placeholder="Filter Keys" size="20" class="super-settings-form-control" title="Filter Keys" id="super-settings-filter" style="margin-right:1rem;">
|
10
10
|
|
11
|
-
<button type="button" class="btn btn-default" id="add-setting"><%= icon_image(:plus) %> Add Setting</button>
|
11
|
+
<button type="button" class="super-settings-btn super-settings-btn-default" id="super-settings-add-setting"><%= icon_image(:plus, style: {"vertical-align": "text-top"}) %> Add Setting</button>
|
12
12
|
|
13
|
-
<button type="button" class="btn btn-default" id="discard-changes" disabled>
|
13
|
+
<button type="button" class="super-settings-btn super-settings-btn-default" id="super-settings-discard-changes" disabled>
|
14
14
|
Discard Changes
|
15
15
|
</button>
|
16
16
|
|
17
|
-
<button type="button" class="btn btn-primary" id="save-settings" disabled>
|
17
|
+
<button type="button" class="super-settings-btn super-settings-btn-primary" id="super-settings-save-settings" disabled>
|
18
18
|
Save <span class="count"></span> Changes
|
19
19
|
</button>
|
20
20
|
|
21
21
|
<strong class="js-flash" style="display:none; margin-left:3rem;"></strong>
|
22
22
|
</div>
|
23
23
|
|
24
|
-
<table class="table table-striped" id="settings-table">
|
24
|
+
<table class="super-settings-table super-settings-table-striped" id="settings-table">
|
25
25
|
<thead>
|
26
26
|
<tr>
|
27
|
-
<th scope="col" class="super-settings-key">
|
27
|
+
<th scope="col" class="super-settings-key">
|
28
|
+
Key
|
29
|
+
<button class="super-settings-sort-control super-settings-btn-no-chrome" data-field="key" data-order="asc" data-selected="true" title="Sort by key">
|
30
|
+
<%= icon_image("arrow-down-short", data: {order: :asc}, style: {display: "inline-block"}) %>
|
31
|
+
<%= icon_image("arrow-up-short", data: {order: :desc}, style: {display: "none"}) %>
|
32
|
+
</button>
|
33
|
+
</th>
|
28
34
|
<th scope="col" class="super-settings-value">Value</th>
|
29
35
|
<th scope="col" class="super-settings-value-type">Type</th>
|
30
36
|
<th scope="col" class="super-settings-description">Description</th>
|
37
|
+
<th scope="col" data-field="updated_at">
|
38
|
+
Modified
|
39
|
+
<button class="super-settings-sort-control super-settings-btn-no-chrome" data-field="updated_at" data-order="asc" title="Sort by modified time">
|
40
|
+
<%= icon_image("arrow-down-short", data: {order: :asc}, style: {display: "inline-block"}) %>
|
41
|
+
<%= icon_image("arrow-up-short", data: {order: :desc}, style: {display: "none"}) %>
|
42
|
+
</button>
|
43
|
+
</th>
|
31
44
|
<th scope="col" class="super-settings-controls"><span class="super-settings-sr-only">Controls</span></th>
|
32
45
|
</tr>
|
33
46
|
</thead>
|
@@ -35,15 +48,15 @@
|
|
35
48
|
</tbody>
|
36
49
|
</table>
|
37
50
|
</form>
|
38
|
-
</main>
|
39
51
|
|
40
|
-
<div id="modal" class="super-settings-modal js-close-modal" aria-hidden="true" aria-role="dialog">
|
41
|
-
|
42
|
-
|
43
|
-
|
52
|
+
<div id="super-settings-modal" class="super-settings-modal js-close-modal" aria-hidden="true" aria-role="dialog">
|
53
|
+
<div class="super-settings-modal-dialog">
|
54
|
+
<button type="button" title="Close Dialog" class="super-settings-modal-close super-settings-btn-no-chrome js-close-modal">×</button>
|
55
|
+
<div class="super-settings-modal-content">
|
56
|
+
</div>
|
44
57
|
</div>
|
45
58
|
</div>
|
46
|
-
</
|
59
|
+
</main>
|
47
60
|
|
48
61
|
<template id="setting-row-template" style="display:none;">
|
49
62
|
<tr>
|
@@ -65,11 +78,15 @@
|
|
65
78
|
<div class="js-value-placeholder super-settings-max-height-text"></div>
|
66
79
|
</td>
|
67
80
|
|
81
|
+
<td class="super-settings-last-modified super-settings-text-nowrap">
|
82
|
+
<div class="js-value-placeholder"></div>
|
83
|
+
</td>
|
84
|
+
|
68
85
|
<td class="super-settings-controls">
|
69
|
-
<%= icon_button(
|
70
|
-
<%= icon_button(
|
71
|
-
<%= icon_button(
|
72
|
-
<%= icon_button(
|
86
|
+
<%= icon_button("info-circle", title: "Setting Info", color: "#0d7ff0", js_class: "js-show-history") %>
|
87
|
+
<%= icon_button("pencil-square", title: "Edit Setting", color: "#0c8024", js_class: "js-edit-setting") %>
|
88
|
+
<%= icon_button("trash3", title: "Remove Setting", color: "#dc3545", js_class: "js-remove-setting") %>
|
89
|
+
<%= icon_button("x-circle", title: "Cancel Changes", color: "#dc3545", js_class: "js-restore-setting", link_style: "display:none;") %>
|
73
90
|
</td>
|
74
91
|
</tr>
|
75
92
|
</template>
|
@@ -79,7 +96,7 @@
|
|
79
96
|
<td class="super-settings-key">
|
80
97
|
<div>
|
81
98
|
<label for="settings_{{id}}_key" class="super-settings-sr-only">Key</label>
|
82
|
-
<input type="text" id="settings_{{id}}_key" name="settings[{{id}}][key]" value="" maxlength="190" class="form-control js-setting-key" required>
|
99
|
+
<input type="text" id="settings_{{id}}_key" name="settings[{{id}}][key]" value="" maxlength="190" class="super-settings-form-control js-setting-key" required>
|
83
100
|
</div>
|
84
101
|
</td>
|
85
102
|
|
@@ -88,72 +105,72 @@
|
|
88
105
|
<label for="settings_{{id}}_value" class="super-settings-sr-only">Value</label>
|
89
106
|
<span class="js-value-placeholder"></span>
|
90
107
|
</div>
|
91
|
-
<div class="container text-danger js-setting-errors" style="display:none;">
|
108
|
+
<div class="super-settings-container super-settings-text-danger js-setting-errors" style="display:none;">
|
92
109
|
</div>
|
93
110
|
</td>
|
94
111
|
|
95
112
|
<td class="super-settings-value-type">
|
96
113
|
<div>
|
97
114
|
<label for="settings_{{id}}_value_type" class="super-settings-sr-only">Value Type</label>
|
98
|
-
<select name="settings[{{id}}][value_type]" class="form-control js-setting-value-type" id="settings_{{id}}_value_type">
|
115
|
+
<select name="settings[{{id}}][value_type]" class="super-settings-form-control js-setting-value-type" id="settings_{{id}}_value_type">
|
99
116
|
<% SuperSettings::Setting::VALUE_TYPES.each do |value_type| %>
|
100
|
-
<option value="<%=
|
117
|
+
<option value="<%= html_escape(value_type) %>"><%= html_escape(value_type) %></option>
|
101
118
|
<% end %>
|
102
119
|
</select>
|
103
120
|
</div>
|
104
121
|
</td>
|
105
122
|
|
106
|
-
<td class="super-settings-description">
|
123
|
+
<td class="super-settings-description" colspan="2">
|
107
124
|
<div>
|
108
125
|
<label for="settings_{{id}}_description" class="super-settings-sr-only">Description</label>
|
109
|
-
<textarea id="settings_{{id}}_description" name="settings[{{id}}][description]" value="" class="form-control" rows="4"></textarea>
|
126
|
+
<textarea id="settings_{{id}}_description" name="settings[{{id}}][description]" value="" class="super-settings-form-control" rows="4"></textarea>
|
110
127
|
</div>
|
111
128
|
</td>
|
112
129
|
|
113
130
|
<td class="super-settings-controls">
|
114
|
-
<%= icon_button(
|
115
|
-
<%= icon_button(
|
116
|
-
<%= icon_button(
|
131
|
+
<%= icon_button("info-circle", title: "Setting Info", color: "#0d7ff0", js_class: "js-show-history") %>
|
132
|
+
<%= icon_button("pencil-square", title: "Edit Setting", color: "#c0c0c0", js_class: "js-no-op", disabled: true) %>
|
133
|
+
<%= icon_button("x-circle", title: "Cancel Changes", color: "#dc3545", js_class: "js-restore-setting") %>
|
117
134
|
</td>
|
118
135
|
</tr>
|
119
136
|
</template>
|
120
137
|
|
121
138
|
<template id="setting-value-field-template" style="display:none;">
|
122
|
-
<textarea id="settings_{{id}}_value" name="settings[{{id}}][value]" class="form-control js-setting-value" rows="4"></textarea>
|
139
|
+
<textarea id="settings_{{id}}_value" name="settings[{{id}}][value]" class="super-settings-form-control js-setting-value" rows="4"></textarea>
|
123
140
|
</template>
|
124
141
|
|
125
142
|
<template id="setting-value-field-integer-template" style="display:none;">
|
126
|
-
<input type="number" step="1" id="settings_{{id}}_value" name="settings[{{id}}][value]" value="" class="form-control js-setting-value">
|
143
|
+
<input type="number" step="1" id="settings_{{id}}_value" name="settings[{{id}}][value]" value="" class="super-settings-form-control js-setting-value">
|
127
144
|
</template>
|
128
145
|
|
129
146
|
<template id="setting-value-field-float-template" style="display:none;">
|
130
|
-
<input type="number" step="any" id="settings_{{id}}_value" name="settings[{{id}}][value]" value="" class="form-control js-setting-value">
|
147
|
+
<input type="number" step="any" id="settings_{{id}}_value" name="settings[{{id}}][value]" value="" class="super-settings-form-control js-setting-value">
|
131
148
|
</template>
|
132
149
|
|
133
150
|
<template id="setting-value-field-datetime-template" style="display:none;">
|
134
151
|
<span>
|
135
|
-
<input type="date" id="settings_{{id}}_value" name="_settings[{{id}}][date]" value="" class="form-control js-date-input">
|
152
|
+
<input type="date" id="settings_{{id}}_value" name="_settings[{{id}}][date]" value="" class="super-settings-form-control js-date-input">
|
136
153
|
<label for="settings_{{id}}_value_time" class="super-settings-sr-only">Time</label>
|
137
|
-
<input type="time" id="settings_{{id}}_value_time" name="_settings[{{id}}][time]" value="" class="form-control js-time-input" aria-label="Time">
|
154
|
+
<input type="time" id="settings_{{id}}_value_time" name="_settings[{{id}}][time]" value="" class="super-settings-form-control js-time-input" aria-label="Time">
|
138
155
|
<input type="hidden" name="settings[{{id}}][value]" value="" class="js-setting-value">
|
139
|
-
<small class="text-muted">Time Zone: <span class="timezone"></span></small>
|
156
|
+
<small class="super-settings-text-muted">Time Zone: <span class="timezone"></span></small>
|
140
157
|
</span>
|
141
158
|
</template>
|
142
159
|
|
143
160
|
<template id="setting-value-field-boolean-template" style="display:none;">
|
144
|
-
<span class="form-check">
|
161
|
+
<span class="super-settings-form-check">
|
145
162
|
<input type="checkbox" id="settings_{{id}}_value" name="settings[{{id}}][value]" value="true" class="js-setting-value">
|
146
163
|
<label for="settings_{{id}}_value">Enabled</label>
|
147
164
|
</span>
|
148
165
|
</template>
|
149
166
|
|
150
167
|
<template id="setting-value-field-array-template" style="display:none;">
|
151
|
-
<textarea id="settings_{{id}}_value" name="settings[{{id}}][value]" value="" class="form-control js-setting-value" rows="8" placeholder="one entry per line"></textarea>
|
168
|
+
<textarea id="settings_{{id}}_value" name="settings[{{id}}][value]" value="" class="super-settings-form-control js-setting-value" rows="8" placeholder="one entry per line"></textarea>
|
152
169
|
</template>
|
153
170
|
|
154
171
|
<template id="setting-history-table" style="display:none">
|
155
172
|
<h3>Setting History: <span class="super-settings-history-key"></span></h3>
|
156
|
-
<table class="table table-striped" id="super-settings-history">
|
173
|
+
<table class="super-settings-table super-settings-table-striped" id="super-settings-history">
|
157
174
|
<thead>
|
158
175
|
<tr>
|
159
176
|
<th scope="col" class="super-settings-text-nowrap">Time</th>
|
@@ -2,9 +2,12 @@
|
|
2
2
|
<html lang="en">
|
3
3
|
<head>
|
4
4
|
<title><%= application_name %> Settings</title>
|
5
|
+
<meta charset="utf-8">
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
7
|
<meta name="pinterest" content="nopin" />
|
7
|
-
<meta name="format-detection" content="telephone=no">
|
8
|
+
<meta name="format-detection" content="telephone=no email=no date=no address=no">
|
9
|
+
<meta name="robots" content="noindex, nofollow">
|
10
|
+
<meta name="referrer" content="no-referrer-when-downgrade">
|
8
11
|
<%= layout_style_tag %>
|
9
12
|
<%= add_to_head %>
|
10
13
|
</head>
|
@@ -15,7 +18,7 @@
|
|
15
18
|
<%= application_header %>
|
16
19
|
</h1>
|
17
20
|
</header>
|
18
|
-
<div class="container">
|
21
|
+
<div class="super-settings-container">
|
19
22
|
<%= yield %>
|
20
23
|
</div>
|
21
24
|
</body>
|
@@ -1,12 +1,14 @@
|
|
1
|
-
* {
|
1
|
+
* {
|
2
|
+
box-sizing: border-box;
|
3
|
+
}
|
2
4
|
|
3
5
|
body {
|
4
6
|
font-family: sans-serif;
|
5
7
|
font-size: 1rem;
|
6
8
|
line-height: 1.5;
|
7
9
|
text-align: left;
|
8
|
-
color:
|
9
|
-
background-color:
|
10
|
+
color: var(--text-color);
|
11
|
+
background-color: var(--background-color);
|
10
12
|
margin: 0;
|
11
13
|
padding: 0;
|
12
14
|
}
|
@@ -37,157 +39,11 @@ header h1.logo img {
|
|
37
39
|
margin-right: 1rem;
|
38
40
|
}
|
39
41
|
|
40
|
-
.align-center {
|
41
|
-
text-align: center;
|
42
|
-
}
|
43
|
-
|
44
|
-
.container {
|
45
|
-
padding-left: 15px;
|
46
|
-
padding-right: 15px;
|
47
|
-
margin-left: auto;
|
48
|
-
margin-right: auto;
|
49
|
-
}
|
50
|
-
|
51
42
|
a {
|
52
43
|
text-decoration: none;
|
53
|
-
color:
|
44
|
+
color: var(--link-color);
|
54
45
|
}
|
55
46
|
|
56
47
|
a:visited {
|
57
|
-
color:
|
58
|
-
}
|
59
|
-
|
60
|
-
.btn {
|
61
|
-
box-shadow:inset 0px 1px 0px 0px #ffffff;
|
62
|
-
background:linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%);
|
63
|
-
background-color:#f9f9f9;
|
64
|
-
border-radius:6px;
|
65
|
-
border:1px solid #dcdcdc;
|
66
|
-
display:inline-block;
|
67
|
-
color:#666666;
|
68
|
-
font-family:Arial;
|
69
|
-
font-size:15px;
|
70
|
-
font-weight:bold;
|
71
|
-
padding:9px 16px;
|
72
|
-
text-decoration:none;
|
73
|
-
text-shadow:0px 1px 0px #ffffff;
|
74
|
-
vertical-align: middle;
|
75
|
-
}
|
76
|
-
.btn:hover {
|
77
|
-
background:linear-gradient(to bottom, #e9e9e9 5%, #f9f9f9 100%);
|
78
|
-
background-color:#e9e9e9;
|
79
|
-
}
|
80
|
-
.btn:active {
|
81
|
-
position:relative;
|
82
|
-
top:1px;
|
83
|
-
}
|
84
|
-
.btn:disabled {
|
85
|
-
background:linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%);
|
86
|
-
background-color:#f9f9f9;
|
87
|
-
opacity: 0.65;
|
88
|
-
box-shadow: none;
|
89
|
-
}
|
90
|
-
|
91
|
-
.btn-primary {
|
92
|
-
box-shadow:inset 0px 1px 0px 0px #9fb4f2;
|
93
|
-
background:linear-gradient(to bottom, #7892c2 5%, #476e9e 100%);
|
94
|
-
background-color:#7892c2;
|
95
|
-
color:#ffffff;
|
96
|
-
text-shadow:0px 1px 0px #283966;
|
97
|
-
}
|
98
|
-
.btn-primary:hover {
|
99
|
-
background:linear-gradient(to bottom, #476e9e 5%, #7892c2 100%);
|
100
|
-
background-color:#476e9e;
|
101
|
-
}
|
102
|
-
.btn-primary:disabled {
|
103
|
-
background:linear-gradient(to bottom, #7892c2 5%, #476e9e 100%);
|
104
|
-
background-color:#7892c2;
|
105
|
-
}
|
106
|
-
|
107
|
-
.btn:not(:disabled) {
|
108
|
-
cursor: pointer;
|
109
|
-
}
|
110
|
-
.btn:disabled {
|
111
|
-
opacity: .65;
|
112
|
-
}
|
113
|
-
|
114
|
-
.table {
|
115
|
-
width: 100%;
|
116
|
-
max-width: 100%;
|
117
|
-
margin-bottom: 1rem;
|
118
|
-
border-collapse: collapse;
|
119
|
-
}
|
120
|
-
|
121
|
-
.table thead th {
|
122
|
-
vertical-align: bottom;
|
123
|
-
border-bottom: 2px solid #dee2e6;
|
124
|
-
}
|
125
|
-
|
126
|
-
.table td, .table th {
|
127
|
-
padding: 0.75rem;
|
128
|
-
vertical-align: top;
|
129
|
-
border-top: 1px solid #dee2e6;
|
130
|
-
}
|
131
|
-
|
132
|
-
.table-striped tbody tr:nth-of-type(odd) {
|
133
|
-
background-color: rgba(0, 0, 0, .05);
|
134
|
-
}
|
135
|
-
|
136
|
-
textarea {
|
137
|
-
font-family: inherit;
|
138
|
-
margin: 0;
|
139
|
-
overflow: auto;
|
140
|
-
resize: vertical;
|
141
|
-
}
|
142
|
-
|
143
|
-
.form-control {
|
144
|
-
font-family: inherit;
|
145
|
-
margin: 0;
|
146
|
-
overflow: visible;
|
147
|
-
display: block;
|
148
|
-
width: 100%;
|
149
|
-
padding: .375rem .75rem;
|
150
|
-
font-size: 1rem;
|
151
|
-
line-height: 1.5;
|
152
|
-
color: #495057;
|
153
|
-
background-color: #fff;
|
154
|
-
background-clip: padding-box;
|
155
|
-
border: 1px solid #ced4da;
|
156
|
-
border-radius: .25rem;
|
157
|
-
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
158
|
-
}
|
159
|
-
|
160
|
-
select.form-control:not([size]):not([multiple]) {
|
161
|
-
height: calc(2.25rem + 2px);
|
162
|
-
}
|
163
|
-
|
164
|
-
.form-check {
|
165
|
-
margin-top: .5rem;
|
166
|
-
display: inline-block;
|
167
|
-
}
|
168
|
-
|
169
|
-
.form-check input[type=checkbox] {
|
170
|
-
vertical-align: middle;
|
171
|
-
}
|
172
|
-
|
173
|
-
.form-inline {
|
174
|
-
display: inline-block;
|
175
|
-
}
|
176
|
-
|
177
|
-
.form-inline .form-control {
|
178
|
-
display: inline-block;
|
179
|
-
width: auto;
|
180
|
-
vertical-align: middle;
|
181
|
-
}
|
182
|
-
|
183
|
-
.text-success {
|
184
|
-
color: green !important;
|
185
|
-
}
|
186
|
-
|
187
|
-
.text-danger {
|
188
|
-
color: firebrick !important;
|
189
|
-
}
|
190
|
-
|
191
|
-
.text-muted {
|
192
|
-
color: #666 !important;
|
48
|
+
color: var(--link-color);
|
193
49
|
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<% unless color_scheme != :dark %>
|
2
|
+
:root {
|
3
|
+
--text-color: #212529;
|
4
|
+
--background-color: #ffffff;
|
5
|
+
--link-color: #369;
|
6
|
+
}
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<% if color_scheme == :system %>
|
10
|
+
@media (prefers-color-scheme: dark) {
|
11
|
+
<% end %>
|
12
|
+
<% if color_scheme == :system || color_scheme == :dark %>
|
13
|
+
:root {
|
14
|
+
--text-color: #fff;
|
15
|
+
--background-color: #333;
|
16
|
+
--link-color: rgb(133, 179, 225);
|
17
|
+
}
|
18
|
+
<% end %>
|
19
|
+
<% if color_scheme == :system %>
|
20
|
+
}
|
21
|
+
<% end %>
|
@@ -15,8 +15,8 @@
|
|
15
15
|
|
16
16
|
// Set the enabled status of the save button for submitting the form.
|
17
17
|
function enableSaveButton() {
|
18
|
-
const saveButton = document.querySelector("#save-settings");
|
19
|
-
const discardButton = document.querySelector("#discard-changes");
|
18
|
+
const saveButton = document.querySelector("#super-settings-save-settings");
|
19
|
+
const discardButton = document.querySelector("#super-settings-discard-changes");
|
20
20
|
if (saveButton) {
|
21
21
|
const count = changesCount();
|
22
22
|
const countSpan = saveButton.querySelector(".count");
|
@@ -117,6 +117,14 @@
|
|
117
117
|
if (setting.description !== null && setting.description !== undefined) {
|
118
118
|
row.querySelector(".super-settings-description .js-value-placeholder").innerHTML = escapeHTML(setting.description).replaceAll("\n", "<br>");
|
119
119
|
}
|
120
|
+
if (setting.updated_at !== null && setting.updated_at !== undefined) {
|
121
|
+
const lastModified = new Date(Date.parse(setting.updated_at));
|
122
|
+
const lastModifiedFormatter = new Intl.DateTimeFormat(navigator.language, {month: "short", day: "numeric", year: "numeric"});
|
123
|
+
const lastModifiedString = lastModifiedFormatter.format(lastModified);
|
124
|
+
const lastModifiedElement = row.querySelector(".super-settings-last-modified .js-value-placeholder")
|
125
|
+
lastModifiedElement.innerText = lastModifiedString;
|
126
|
+
lastModifiedElement.title = dateFormatter().format(lastModified);
|
127
|
+
}
|
120
128
|
|
121
129
|
return row
|
122
130
|
}
|
@@ -182,6 +190,7 @@
|
|
182
190
|
function editSettingRow(setting) {
|
183
191
|
const row = elementFromSettingTemplate(setting, "#setting-row-edit-template");
|
184
192
|
row.dataset.id = setting.id
|
193
|
+
row.dataset.key = setting.key
|
185
194
|
|
186
195
|
row.querySelector(".super-settings-key input").value = setting.key;
|
187
196
|
if (setting.description) {
|
@@ -239,7 +248,7 @@
|
|
239
248
|
document.querySelector("#settings-table tbody").prepend(row);
|
240
249
|
}
|
241
250
|
bindSettingControlEvents(row);
|
242
|
-
filterSettings(document.querySelector("#filter").value);
|
251
|
+
filterSettings(document.querySelector("#super-settings-filter").value);
|
243
252
|
row.scrollIntoView({block: "nearest"});
|
244
253
|
enableSaveButton();
|
245
254
|
return row;
|
@@ -301,7 +310,7 @@
|
|
301
310
|
|
302
311
|
// Programatically apply the filter again to keep it up to date with other changes.
|
303
312
|
function applyFilter(value) {
|
304
|
-
const filter = document.querySelector("#filter");
|
313
|
+
const filter = document.querySelector("#super-settings-filter");
|
305
314
|
if (filter) {
|
306
315
|
if (value) {
|
307
316
|
filter.value = value;
|
@@ -330,11 +339,11 @@
|
|
330
339
|
function showFlash(message, success) {
|
331
340
|
const flash = document.querySelector(".js-flash");
|
332
341
|
if (success) {
|
333
|
-
flash.classList.add("text-success");
|
334
|
-
flash.classList.remove("text-danger");
|
342
|
+
flash.classList.add("super-settings-text-success");
|
343
|
+
flash.classList.remove("super-settings-text-danger");
|
335
344
|
} else {
|
336
|
-
flash.classList.add("
|
337
|
-
flash.classList.remove("text-success");
|
345
|
+
flash.classList.add("tsuper-settings-ext-danger");
|
346
|
+
flash.classList.remove("super-settings-text-success");
|
338
347
|
}
|
339
348
|
flash.innerText = message;
|
340
349
|
flash.style.display = "inline-block";
|
@@ -378,7 +387,7 @@
|
|
378
387
|
tbody.insertAdjacentHTML("beforeend", rowsHTML);
|
379
388
|
|
380
389
|
if (payload.previous_page_params || payload.next_page_params) {
|
381
|
-
let paginationHTML = `<div class="align-center">`;
|
390
|
+
let paginationHTML = `<div class="super-settings-align-center">`;
|
382
391
|
if (payload.previous_page_params) {
|
383
392
|
paginationHTML += `<div style="float:left;"><a href="#" class="js-show-history" title="Newer" data-offset="${payload.previous_page_params.offset}" data-limit="${payload.previous_page_params.limit}" data-key="${payload.previous_page_params.key}")>← Newer</a></div>`;
|
384
393
|
}
|
@@ -393,7 +402,7 @@
|
|
393
402
|
|
394
403
|
// Show a modal window overlayed on the page.
|
395
404
|
function showModal() {
|
396
|
-
const modal = document.querySelector("#modal");
|
405
|
+
const modal = document.querySelector("#super-settings-modal");
|
397
406
|
const content = document.querySelector(".super-settings-modal-content");
|
398
407
|
modal.style.display = "block";
|
399
408
|
modal.setAttribute("aria-hidden", "false");
|
@@ -409,7 +418,7 @@
|
|
409
418
|
|
410
419
|
// Hide the modal window overlayed on the page.
|
411
420
|
function hideModal() {
|
412
|
-
const modal = document.querySelector("#modal");
|
421
|
+
const modal = document.querySelector("#super-settings-modal");
|
413
422
|
const content = document.querySelector(".super-settings-modal-content");
|
414
423
|
modal.style.display = "none";
|
415
424
|
modal.setAttribute("aria-hidden", "true");
|
@@ -456,7 +465,7 @@
|
|
456
465
|
return;
|
457
466
|
}
|
458
467
|
|
459
|
-
const modal = document.querySelector("#modal");
|
468
|
+
const modal = document.querySelector("#super-settings-modal");
|
460
469
|
const content = document.querySelector(".super-settings-modal-content");
|
461
470
|
let key = event.target.dataset.key;
|
462
471
|
if (!key) {
|
@@ -592,7 +601,12 @@
|
|
592
601
|
document.querySelectorAll("#settings-table tbody tr[data-edited=true]").forEach(function(row) {
|
593
602
|
const data = {};
|
594
603
|
settingsData.push(data);
|
604
|
+
|
595
605
|
data.key = row.querySelector(".js-setting-key").value;
|
606
|
+
if (data.key != row.dataset.key) {
|
607
|
+
data.key_was = row.dataset.key;
|
608
|
+
}
|
609
|
+
|
596
610
|
const deleted = row.querySelector(".js-setting-deleted");
|
597
611
|
if (deleted && deleted.value === "1") {
|
598
612
|
data.deleted = true;
|
@@ -635,7 +649,7 @@
|
|
635
649
|
function refreshPage(event) {
|
636
650
|
event.preventDefault();
|
637
651
|
let url = window.location.href.replace(/\?.*/, "");
|
638
|
-
const filter = document.querySelector("#filter").value;
|
652
|
+
const filter = document.querySelector("#super-settings-filter").value;
|
639
653
|
if (filter !== "") {
|
640
654
|
url += "?filter=" + escape(filter);
|
641
655
|
}
|
@@ -694,8 +708,9 @@
|
|
694
708
|
const tbody = document.querySelector("#settings-table tbody");
|
695
709
|
tbody.innerHTML = "";
|
696
710
|
let count = settings.length;
|
697
|
-
|
698
|
-
|
711
|
+
|
712
|
+
sortSettings(settings).forEach(function(setting) {
|
713
|
+
const randomId = "setting" + Math.floor((Math.random() * 0xFFFFFFFFFFFFF)).toString(16);
|
699
714
|
setting.id = (setting.id || randomId);
|
700
715
|
const row = settingRow(setting);
|
701
716
|
tbody.appendChild(row);
|
@@ -703,12 +718,73 @@
|
|
703
718
|
});
|
704
719
|
document.querySelector(".js-settings-count").textContent = `${count} ${count === 1 ? "Setting" : "Settings"}`;
|
705
720
|
|
706
|
-
const filter = document.querySelector("#filter");
|
721
|
+
const filter = document.querySelector("#super-settings-filter");
|
707
722
|
if (filter) {
|
708
723
|
filter.dispatchEvent(new Event("input"));
|
709
724
|
}
|
710
725
|
}
|
711
726
|
|
727
|
+
function sortOrder() {
|
728
|
+
const selectedSort = document.querySelector(".super-settings-sort-control[data-selected=true]");
|
729
|
+
const field = selectedSort.dataset.field;
|
730
|
+
const order = selectedSort.dataset.order;
|
731
|
+
return {field: field, order: order};
|
732
|
+
}
|
733
|
+
|
734
|
+
// Sort settings by the selected sort option.
|
735
|
+
function sortSettings(settings) {
|
736
|
+
const sort = sortOrder();
|
737
|
+
return settings.sort(function(a, b) {
|
738
|
+
let aValue = a[sort.field];
|
739
|
+
let bValue = b[sort.field];
|
740
|
+
if (sort.field == "updated_at") {
|
741
|
+
aValue = new Date(Date.parse(aValue));
|
742
|
+
bValue = new Date(Date.parse(bValue));
|
743
|
+
}
|
744
|
+
|
745
|
+
if (aValue === bValue) {
|
746
|
+
return 0;
|
747
|
+
} else if (sort.order === "asc") {
|
748
|
+
return (aValue < bValue) ? -1 : 1;
|
749
|
+
} else {
|
750
|
+
return (aValue > bValue) ? -1 : 1;
|
751
|
+
}
|
752
|
+
})
|
753
|
+
}
|
754
|
+
|
755
|
+
function setSortOrder(event) {
|
756
|
+
event.preventDefault();
|
757
|
+
|
758
|
+
const target = event.target.closest(".super-settings-sort-control");
|
759
|
+
let prevSelection = document.querySelector(".super-settings-sort-control[data-selected=true]");
|
760
|
+
|
761
|
+
if (prevSelection == target) {
|
762
|
+
selectSortElement(prevSelection, false);
|
763
|
+
target.querySelector(`[data-order=${target.dataset.order}]`).style.display = "none";
|
764
|
+
target.dataset.order = (target.dataset.order === "asc" ? "desc" : "asc");
|
765
|
+
target.querySelector(`[data-order=${target.dataset.order}]`).style.display = "inline-block";
|
766
|
+
} else {
|
767
|
+
selectSortElement(prevSelection, false);
|
768
|
+
}
|
769
|
+
|
770
|
+
selectSortElement(target, true);
|
771
|
+
|
772
|
+
renderSettingsTable(activeSettings);
|
773
|
+
}
|
774
|
+
|
775
|
+
function selectSortElement(element, selected) {
|
776
|
+
element.dataset.selected = selected;
|
777
|
+
|
778
|
+
const svg = element.querySelector(`[data-order=${element.dataset.order}]`).querySelector("svg");
|
779
|
+
if (selected) {
|
780
|
+
svg.style.backgroundColor = getComputedStyle(document.querySelector(".super-settings")).getPropertyValue("--primary-color");
|
781
|
+
svg.style.fill = "white";
|
782
|
+
} else {
|
783
|
+
svg.style.backgroundColor = null;
|
784
|
+
svg.style.fill = null;
|
785
|
+
}
|
786
|
+
}
|
787
|
+
|
712
788
|
function promptUnsavedChanges(event) {
|
713
789
|
if (changesCount() > 0) {
|
714
790
|
return "Are you sure you want to leave?";
|
@@ -740,15 +816,18 @@
|
|
740
816
|
docReady(function() {
|
741
817
|
storeAccessToken();
|
742
818
|
|
743
|
-
addListener(document.querySelector("#filter"), "input", filterListener);
|
744
|
-
addListener(document.querySelector("#add-setting"), "click", addSetting);
|
745
|
-
addListener(document.querySelector("#discard-changes"), "click", refreshPage);
|
746
|
-
addListener(document.querySelector("#save-settings"), "click", updateSettings);
|
747
|
-
addListener(document.querySelector("#modal"), "click", closeModal);
|
819
|
+
addListener(document.querySelector("#super-settings-filter"), "input", filterListener);
|
820
|
+
addListener(document.querySelector("#super-settings-add-setting"), "click", addSetting);
|
821
|
+
addListener(document.querySelector("#super-settings-discard-changes"), "click", refreshPage);
|
822
|
+
addListener(document.querySelector("#super-settings-save-settings"), "click", updateSettings);
|
823
|
+
addListener(document.querySelector("#super-settings-modal"), "click", closeModal);
|
824
|
+
addListener(document.querySelectorAll(".super-settings-sort-control"), "click", setSortOrder);
|
748
825
|
|
749
826
|
const queryParams = new URLSearchParams(window.location.search);
|
750
827
|
applyFilter(queryParams.get("filter"));
|
751
828
|
|
829
|
+
selectSortElement(document.querySelector(".super-settings-sort-control[data-selected=true]"), true);
|
830
|
+
|
752
831
|
fetchActiveSettings();
|
753
832
|
|
754
833
|
window.onbeforeunload = promptUnsavedChanges;
|