super_settings 2.4.3 → 2.5.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/AGENTS.md +27 -0
- data/ARCHITECTURE.md +232 -0
- data/CHANGELOG.md +23 -0
- data/README.md +49 -0
- data/VERSION +1 -1
- data/app/helpers/super_settings/settings_helper.rb +4 -11
- data/app/locales/ar.json +44 -0
- data/app/locales/cs.json +44 -0
- data/app/locales/da.json +44 -0
- data/app/locales/de.json +44 -0
- data/app/locales/el.json +44 -0
- data/app/locales/en.json +55 -0
- data/app/locales/es.json +44 -0
- data/app/locales/fa.json +44 -0
- data/app/locales/fr.json +44 -0
- data/app/locales/gd.json +44 -0
- data/app/locales/he.json +44 -0
- data/app/locales/hi.json +44 -0
- data/app/locales/it.json +44 -0
- data/app/locales/ja.json +44 -0
- data/app/locales/ko.json +44 -0
- data/app/locales/lt.json +44 -0
- data/app/locales/nb.json +44 -0
- data/app/locales/nl.json +44 -0
- data/app/locales/pl.json +44 -0
- data/app/locales/pt-br.json +44 -0
- data/app/locales/pt.json +44 -0
- data/app/locales/ru.json +44 -0
- data/app/locales/sv.json +44 -0
- data/app/locales/ta.json +44 -0
- data/app/locales/tr.json +44 -0
- data/app/locales/uk.json +44 -0
- data/app/locales/ur.json +44 -0
- data/app/locales/vi.json +44 -0
- data/app/locales/zh-cn.json +44 -0
- data/app/locales/zh-tw.json +44 -0
- data/app/views/layouts/super_settings/settings.html.erb +4 -4
- data/config/routes.rb +2 -0
- data/lib/super_settings/application/api.js +37 -12
- data/lib/super_settings/application/helper.rb +70 -11
- data/lib/super_settings/application/index.html.erb +44 -44
- data/lib/super_settings/application/layout.html.erb +57 -6
- data/lib/super_settings/application/layout_styles.css +274 -21
- data/lib/super_settings/application/layout_vars.css.erb +11 -7
- data/lib/super_settings/application/scripts.js +72 -13
- data/lib/super_settings/application/style_vars.css.erb +104 -51
- data/lib/super_settings/application/styles.css +179 -84
- data/lib/super_settings/application.rb +16 -1
- data/lib/super_settings/controller_actions.rb +33 -1
- data/lib/super_settings/http_client.rb +2 -1
- data/lib/super_settings/local_cache.rb +12 -16
- data/lib/super_settings/mini_i18n.rb +110 -0
- data/lib/super_settings/rack_application.rb +84 -5
- data/lib/super_settings/rest_api.rb +7 -3
- data/lib/super_settings/setting.rb +1 -1
- data/lib/super_settings/storage/active_record_storage/models.rb +7 -9
- data/lib/super_settings/storage/http_storage.rb +1 -2
- data/lib/super_settings/storage/json_storage.rb +1 -1
- data/lib/super_settings/storage/mongodb_storage.rb +2 -1
- data/lib/super_settings/storage/s3_storage.rb +1 -1
- data/lib/super_settings/storage.rb +1 -1
- data/lib/super_settings/version.rb +1 -1
- data/lib/super_settings.rb +16 -18
- data/super_settings.gemspec +2 -1
- metadata +35 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5417df66afb91b92e9142075a083883d6884a5f148858b43738cafb4bbe5aea3
|
|
4
|
+
data.tar.gz: 7156046f2de10818424ff1997a1aea922ea5c67ebea1c0fe2ce8ffbb5f8a9746
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a8fd1761f7cf0eeee7b30d06ea1dc7b766dde492c3b8786fb549469ee76e1d81321696ea1d8bef1a272896be6992ab5af598cf521e4c91090602f5fe809de146
|
|
7
|
+
data.tar.gz: fc346701a55ad717e806d234780df064aebe15d981e1e5da65c4d435bcb6b8b13d6b5ac240d654e827e167ebd083dbb8e4319831bb7aa09aba94b44ac27b8f7f
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## Coding style
|
|
2
|
+
|
|
3
|
+
Always include the # frozen_string_literal: true magic comment at the top of each ruby file.
|
|
4
|
+
|
|
5
|
+
Use `class << self` syntax for defining class methods. instead of `def self.method_name`.
|
|
6
|
+
|
|
7
|
+
All public methods should have YARD documentation. Include an empty comment line between the method description and the first YARD tag.
|
|
8
|
+
|
|
9
|
+
This project uses the standardrb style guide. Run `bundle exec standardrb --fix` to automatically fix style issues.
|
|
10
|
+
|
|
11
|
+
Do not rewrite existing code just to satisfy style guidelines unless those are violations of the standardrb rules.
|
|
12
|
+
|
|
13
|
+
Do not use suffixed conditionals with complex conditions with multiple logical operators. Use full `if`/`unless` blocks instead. Do not convert existing code to use suffixed conditionals if it is already using block conditionals.
|
|
14
|
+
|
|
15
|
+
Use [:symbol_1, :symbol_2] syntax instead of %i[symbol_1 symbol_2] for arrays of symbols.
|
|
16
|
+
|
|
17
|
+
Use ["string1", "string2"] syntax instead of %w[string1 string2] for single line arrays of strings.
|
|
18
|
+
|
|
19
|
+
Use double quotes for strings instead of single quotes.
|
|
20
|
+
|
|
21
|
+
Do not change existing code to break existing line length unless absolutely necessary. New code should adhere to a 100 character line length limit.
|
|
22
|
+
|
|
23
|
+
Use `raise SomeError.new("message")` instead of `raise SomeError, "message"` for raising exceptions.
|
|
24
|
+
|
|
25
|
+
## Testing
|
|
26
|
+
|
|
27
|
+
Run the test suite with `bundle exec rspec`.
|
data/ARCHITECTURE.md
CHANGED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# SuperSettings Architecture
|
|
2
|
+
|
|
3
|
+
SuperSettings is a Ruby gem for managing dynamic application settings at runtime. Settings are persisted in a storage backend and cached in memory for fast, low-latency reads.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## High-Level Overview
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
graph TD
|
|
11
|
+
App["Application Code"] -->|"SuperSettings.get(key)"| Cache["Local Cache"]
|
|
12
|
+
Cache -->|"cache miss / refresh"| Model["Setting Model"]
|
|
13
|
+
Model -->|"read/write"| Storage["Storage Backend"]
|
|
14
|
+
|
|
15
|
+
Admin["Admin User"] -->|"HTTP"| WebUI["Web UI"]
|
|
16
|
+
WebUI -->|"REST calls"| API["REST API"]
|
|
17
|
+
API -->|"bulk_update"| Model
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Core Components
|
|
23
|
+
|
|
24
|
+
```mermaid
|
|
25
|
+
graph LR
|
|
26
|
+
subgraph Core
|
|
27
|
+
SM["SuperSettings module\n(global accessors)"]
|
|
28
|
+
LC["LocalCache\n(in-memory, thread-safe)"]
|
|
29
|
+
Setting["Setting\n(model + validation)"]
|
|
30
|
+
Coerce["Coerce\n(type conversion)"]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
SM --> LC
|
|
34
|
+
LC --> Setting
|
|
35
|
+
Setting --> Coerce
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Component | Responsibility |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `SuperSettings` | Public API — `get`, `integer`, `float`, `enabled?`, `datetime`, `array`, `rand` |
|
|
41
|
+
| `LocalCache` | Thread-safe in-memory cache with periodic delta refresh |
|
|
42
|
+
| `Setting` | Typed setting model with validation, change tracking, and bulk update |
|
|
43
|
+
| `Coerce` | Type coercion for string, integer, float, boolean, datetime, array |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Setting Value Types
|
|
48
|
+
|
|
49
|
+
```mermaid
|
|
50
|
+
graph LR
|
|
51
|
+
Types["Value Types"] --> S["string"]
|
|
52
|
+
Types --> I["integer"]
|
|
53
|
+
Types --> F["float"]
|
|
54
|
+
Types --> B["boolean"]
|
|
55
|
+
Types --> D["datetime"]
|
|
56
|
+
Types --> A["array"]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Storage Layer
|
|
62
|
+
|
|
63
|
+
Storage backends implement a common interface. The active backend is selected at configuration time.
|
|
64
|
+
|
|
65
|
+
```mermaid
|
|
66
|
+
graph TD
|
|
67
|
+
Setting["Setting Model"] --> StorageInterface["Storage Interface"]
|
|
68
|
+
StorageInterface --> AR["ActiveRecordStorage\n(SQL database)"]
|
|
69
|
+
StorageInterface --> Redis["RedisStorage\n(Redis)"]
|
|
70
|
+
StorageInterface --> HTTP["HttpStorage\n(remote REST API)"]
|
|
71
|
+
StorageInterface --> S3["S3Storage\n(AWS S3 JSON file)"]
|
|
72
|
+
StorageInterface --> Mongo["MongoDBStorage\n(MongoDB)"]
|
|
73
|
+
StorageInterface --> JSON["JSONStorage\n(JSON file, abstract base)"]
|
|
74
|
+
StorageInterface --> Null["NullStorage\n(no-op, for CI)"]
|
|
75
|
+
StorageInterface --> Test["TestStorage\n(in-memory, for tests)"]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Storage Interface
|
|
79
|
+
|
|
80
|
+
Each backend implements:
|
|
81
|
+
- `all` / `active` / `updated_since(time)` — bulk reads
|
|
82
|
+
- `find_by_key(key)` — single lookup
|
|
83
|
+
- `last_updated_at` — used for delta refresh
|
|
84
|
+
- `save!` — persist a setting
|
|
85
|
+
- `create_history` — record a change event
|
|
86
|
+
- `load_asynchronous?` — whether initial load can be deferred to a background thread
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Caching and Refresh
|
|
91
|
+
|
|
92
|
+
```mermaid
|
|
93
|
+
sequenceDiagram
|
|
94
|
+
participant App
|
|
95
|
+
participant LC as LocalCache
|
|
96
|
+
participant DB as Storage Backend
|
|
97
|
+
|
|
98
|
+
App->>LC: get(key)
|
|
99
|
+
alt cache cold
|
|
100
|
+
LC->>DB: active() — load all settings
|
|
101
|
+
DB-->>LC: settings[]
|
|
102
|
+
LC-->>App: value
|
|
103
|
+
else cache warm, interval elapsed
|
|
104
|
+
LC->>DB: last_updated_at()
|
|
105
|
+
alt data changed
|
|
106
|
+
LC->>DB: updated_since(last_refresh)
|
|
107
|
+
DB-->>LC: changed settings[]
|
|
108
|
+
LC->>LC: merge into frozen cache
|
|
109
|
+
end
|
|
110
|
+
LC-->>App: value
|
|
111
|
+
else cache warm, interval not elapsed
|
|
112
|
+
LC-->>App: value (from cache)
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Key properties:
|
|
117
|
+
- Default refresh interval: **5 seconds**
|
|
118
|
+
- `last_updated_at` is itself cached (60s TTL) to reduce storage queries
|
|
119
|
+
- Refresh is delta-based — only changed settings are reloaded
|
|
120
|
+
- The cache is an **immutable frozen hash** replaced atomically on each refresh
|
|
121
|
+
- Initial load can be **asynchronous** (background thread) for some backends
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Request Context
|
|
126
|
+
|
|
127
|
+
Within a request or job, settings are snapshotted so the same key always returns the same value and random numbers are seeded for consistent probabilistic feature flags.
|
|
128
|
+
|
|
129
|
+
```mermaid
|
|
130
|
+
sequenceDiagram
|
|
131
|
+
participant MW as Context Middleware
|
|
132
|
+
participant App as Request Handler
|
|
133
|
+
participant SS as SuperSettings
|
|
134
|
+
|
|
135
|
+
MW->>SS: context { ... }
|
|
136
|
+
SS->>SS: snapshot current settings
|
|
137
|
+
SS->>App: yield
|
|
138
|
+
App->>SS: get(key) — returns snapshot value
|
|
139
|
+
App->>SS: rand(key) — seeded RNG
|
|
140
|
+
SS-->>App: consistent values
|
|
141
|
+
SS->>SS: clear snapshot
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Context is propagated via a thread-local variable and is supported in:
|
|
145
|
+
- Rack requests — `Context::RackMiddleware`
|
|
146
|
+
- Sidekiq jobs — `Context::SidekiqMiddleware`
|
|
147
|
+
- ActiveJob — injected by the Rails Engine
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Web Interface and REST API
|
|
152
|
+
|
|
153
|
+
```mermaid
|
|
154
|
+
graph TD
|
|
155
|
+
Browser["Browser / API Client"] -->|HTTP| RackApp["RackApplication\n(routing + auth)"]
|
|
156
|
+
RackApp -->|reads/writes| RestAPI["RestAPI\n(endpoint logic)"]
|
|
157
|
+
RestAPI --> Setting["Setting Model"]
|
|
158
|
+
|
|
159
|
+
RackApp -->|renders HTML| Application["Application\n(Web UI / ERB templates)"]
|
|
160
|
+
Application -->|JS calls| RestAPI
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### REST Endpoints
|
|
164
|
+
|
|
165
|
+
| Method | Path | Description |
|
|
166
|
+
|---|---|---|
|
|
167
|
+
| GET | `/` | List all active settings |
|
|
168
|
+
| GET | `/setting` | Fetch a single setting by key |
|
|
169
|
+
| POST | `/settings` | Bulk update settings (atomic) |
|
|
170
|
+
| GET | `/history` | Change history for a setting |
|
|
171
|
+
| GET | `/settings/last_updated_at` | Timestamp of most recent change |
|
|
172
|
+
| GET | `/settings/updated_since` | Settings changed after a given time |
|
|
173
|
+
|
|
174
|
+
### Authentication
|
|
175
|
+
|
|
176
|
+
`RackApplication` exposes hooks to integrate with any auth system:
|
|
177
|
+
- `authenticated?` — gate all access
|
|
178
|
+
- `allow_read?` / `allow_write?` — fine-grained access control
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Rails Integration
|
|
183
|
+
|
|
184
|
+
```mermaid
|
|
185
|
+
graph TD
|
|
186
|
+
Engine["SuperSettings::Engine\n(Rails::Engine)"] -->|mounts| Routes["Routes\n(/settings)"]
|
|
187
|
+
Engine -->|inserts| RackMW["Context::RackMiddleware"]
|
|
188
|
+
Engine -->|hooks| ActiveJob["ActiveJob context"]
|
|
189
|
+
Engine -->|hooks| Sidekiq["Sidekiq context\n(if present)"]
|
|
190
|
+
Engine -->|creates| Controller["Dynamic Controller\n(configurable superclass)"]
|
|
191
|
+
Controller --> RackApp["RackApplication"]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The engine auto-configures when mounted:
|
|
195
|
+
- Inserts context middleware into the Rack stack
|
|
196
|
+
- Wraps ActiveJob and Sidekiq execution in a settings context
|
|
197
|
+
- Provides a controller with configurable authentication and layout
|
|
198
|
+
- Triggers settings load after `Rails.application` initializes
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Audit History
|
|
203
|
+
|
|
204
|
+
Every setting change is recorded as a history entry.
|
|
205
|
+
|
|
206
|
+
```mermaid
|
|
207
|
+
graph LR
|
|
208
|
+
Update["Setting#save!"] -->|creates| History["HistoryItem\n(key, value, changed_by, created_at)"]
|
|
209
|
+
RestAPI -->|"history(key)"| History
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Component Dependency Summary
|
|
215
|
+
|
|
216
|
+
```mermaid
|
|
217
|
+
graph TD
|
|
218
|
+
SuperSettings --> LocalCache
|
|
219
|
+
SuperSettings --> Context
|
|
220
|
+
LocalCache --> Setting
|
|
221
|
+
Setting --> Storage
|
|
222
|
+
Setting --> Coerce
|
|
223
|
+
Setting --> HistoryItem
|
|
224
|
+
RackApplication --> RestAPI
|
|
225
|
+
RackApplication --> Application
|
|
226
|
+
RestAPI --> Setting
|
|
227
|
+
Engine --> RackApplication
|
|
228
|
+
Engine --> Context
|
|
229
|
+
HttpStorage --> HttpClient
|
|
230
|
+
S3Storage --> JSONStorage
|
|
231
|
+
S3Storage --> HttpClient
|
|
232
|
+
```
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## 2.5.0
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Updated web UI to match the web UI from the ultra_settings gem. UltraSettings now has a tighter integration with SuperSettings and can be setup to update SuperSettings settings directly from its web UI.
|
|
12
|
+
- Added ability to authorize requests with read only permissions. When read only permissions are enabled, users can view settings in the web UI but cannot edit them. API requests that attempt to modify settings will be rejected with a 403 Forbidden response.
|
|
13
|
+
- Added internationalization (i18n) support for the web UI with translations for 29 languages. The locale is resolved from a `lang` query parameter, a `super_settings_locale` cookie, or the `Accept-Language` header.
|
|
14
|
+
- Added `/authorized` API endpoint that returns the current user's permission level (`read-only` or `read-write`).
|
|
15
|
+
- Added `/api.js` endpoint for serving the JavaScript API client separately.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Fixed S3Storage `path=` setter which incorrectly produced a literal string containing `.chomp('/')` instead of calling the method, causing all S3 object key lookups to use a malformed path.
|
|
20
|
+
- Fixed `bulk_update` silently ignoring a request to delete a non-existent setting key. Previously it would raise an `InvalidRecordError` instead of treating the operation as a no-op.
|
|
21
|
+
- Fixed `RestAPI.last_updated_at` raising a `NoMethodError` when called with an empty settings store (no settings yet created).
|
|
22
|
+
- Fixed `HttpClient` ignoring the `user` and `password` constructor arguments. HTTP Basic auth credentials are now correctly applied to all requests.
|
|
23
|
+
- Fixed `HttpClient` producing a malformed query string (leading `&`) when the base URI includes query parameters but no per-request parameters are provided.
|
|
24
|
+
- Fixed `HttpStorage#reload` making two redundant HTTP requests and discarding the result of the first.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Minimum Ruby version is now 2.7.
|
|
29
|
+
|
|
7
30
|
## 2.4.3
|
|
8
31
|
|
|
9
32
|
### Fixed
|
data/README.md
CHANGED
|
@@ -219,6 +219,55 @@ SuperSettings.web_ui_javascript = "SuperSettingsAPI.headers['Authorization'] = w
|
|
|
219
219
|
|
|
220
220
|
You can also specify the URL for a login page with `SuperSettings.authentication_url`. Browsers will be redirected to this URL if a request requiring authentication is received.
|
|
221
221
|
|
|
222
|
+
#### Read-Only Access
|
|
223
|
+
|
|
224
|
+
You can grant users read-only access to the settings UI. In read-only mode, the web UI will display all settings and their history normally, but the Add, Edit, Delete, Save, and Discard buttons will be hidden. Write API endpoints (`POST /settings`) will return a 403 status.
|
|
225
|
+
|
|
226
|
+
**Rails applications** can use the `super_settings_read_only!` helper method. Call it in a `before_action` to restrict the current request to read-only access:
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
SuperSettings.configure do |config|
|
|
230
|
+
config.controller.enhance do
|
|
231
|
+
before_action do
|
|
232
|
+
redirect_to login_url if current_user.nil?
|
|
233
|
+
|
|
234
|
+
super_settings_read_only! unless current_user.admin?
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
You can also check the current state with `super_settings_read_only?`.
|
|
241
|
+
|
|
242
|
+
**Rack applications** can override the `allow_write?` method on `SuperSettings::RackApplication`. When `allow_write?` returns `false`, the web UI will render in read-only mode and POST requests will be rejected:
|
|
243
|
+
|
|
244
|
+
```ruby
|
|
245
|
+
app = SuperSettings::RackApplication.new do
|
|
246
|
+
def current_user(request)
|
|
247
|
+
# ...
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def allow_write?(user)
|
|
251
|
+
user.admin?
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Middleware-based approach:** You can also set the `super_settings.read_only` key in the Rack environment from any middleware. This works with both the Rails engine and the Rack application:
|
|
257
|
+
|
|
258
|
+
```ruby
|
|
259
|
+
class ReadOnlySettingsMiddleware
|
|
260
|
+
def initialize(app)
|
|
261
|
+
@app = app
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def call(env)
|
|
265
|
+
env["super_settings.read_only"] = true unless admin_user?(env)
|
|
266
|
+
@app.call(env)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
```
|
|
270
|
+
|
|
222
271
|
### Rails Engine
|
|
223
272
|
|
|
224
273
|
The gem ships with a Rails engine that provides easy integration with a Rails application.
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.5.0
|
|
@@ -13,21 +13,14 @@ module SuperSettings
|
|
|
13
13
|
|
|
14
14
|
# Return the application name set by the configuration or a default value.
|
|
15
15
|
def super_settings_application_name
|
|
16
|
-
SuperSettings.configuration.controller.application_name
|
|
16
|
+
SuperSettings.configuration.controller.application_name
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
# Render the header for the web pages using values set in the configuration.
|
|
20
|
+
#
|
|
21
|
+
# @return [String]
|
|
20
22
|
def super_settings_application_header
|
|
21
|
-
|
|
22
|
-
content = "#{super_settings_application_name} Settings"
|
|
23
|
-
if Coerce.present?(config.application_logo)
|
|
24
|
-
content = image_tag(config.application_logo, alt: "").concat(content)
|
|
25
|
-
end
|
|
26
|
-
if config.application_link
|
|
27
|
-
link_to(content, config.application_link)
|
|
28
|
-
else
|
|
29
|
-
content
|
|
30
|
-
end
|
|
23
|
+
SuperSettings::Helper.application_header.html_safe
|
|
31
24
|
end
|
|
32
25
|
|
|
33
26
|
private
|
data/app/locales/ar.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"page.title_suffix": "الإعدادات",
|
|
3
|
+
"page.brand_title": "SuperSettings",
|
|
4
|
+
"filter.label": "تصفية",
|
|
5
|
+
"filter.placeholder": "مفاتيح التصفية",
|
|
6
|
+
"button.add_setting": "إضافة إعداد",
|
|
7
|
+
"button.discard_changes": "تجاهل التغييرات",
|
|
8
|
+
"button.save": "حفظ",
|
|
9
|
+
"button.save_changes": "التغييرات",
|
|
10
|
+
"sort.label": "فرز بواسطة:",
|
|
11
|
+
"sort.key": "المفتاح",
|
|
12
|
+
"sort.modified": "معدل",
|
|
13
|
+
"modal.close": "إغلاق الحوار",
|
|
14
|
+
"card.key": "المفتاح:",
|
|
15
|
+
"card.value": "القيمة:",
|
|
16
|
+
"card.type": "النوع:",
|
|
17
|
+
"card.description": "الوصف:",
|
|
18
|
+
"card.modified": "معدل:",
|
|
19
|
+
"card.info_title": "معلومات الإعداد",
|
|
20
|
+
"card.edit_title": "تعديل الإعداد",
|
|
21
|
+
"card.remove_title": "إزالة الإعداد",
|
|
22
|
+
"card.cancel_title": "إلغاء التغييرات",
|
|
23
|
+
"edit.key_placeholder": "مفتاح الإعداد",
|
|
24
|
+
"edit.description_placeholder": "وصف هذا الإعداد",
|
|
25
|
+
"edit.enabled": "مفعل",
|
|
26
|
+
"edit.array_placeholder": "إدخال واحد لكل سطر",
|
|
27
|
+
"edit.timezone_label": "المنطقة الزمنية:",
|
|
28
|
+
"history.title": "سجل الإعداد:",
|
|
29
|
+
"history.time": "الوقت",
|
|
30
|
+
"history.changed_by": "تم التغيير بواسطة",
|
|
31
|
+
"history.value": "القيمة",
|
|
32
|
+
"history.deleted": "محذوف",
|
|
33
|
+
"history.newer": "أحدث",
|
|
34
|
+
"history.older": "أقدم",
|
|
35
|
+
"count.setting": "إعداد",
|
|
36
|
+
"count.settings": "إعدادات",
|
|
37
|
+
"prompt.unsaved": "هل أنت متأكد أنك تريد المغادرة؟",
|
|
38
|
+
"flash.saved": "تم حفظ الإعدادات",
|
|
39
|
+
"flash.save_failed": "فشل في حفظ الإعدادات",
|
|
40
|
+
"error.generic": "عذراً، حدث خطأ. قم بتحديث الصفحة وحاول مرة أخرى.",
|
|
41
|
+
"language.label": "اللغة",
|
|
42
|
+
"language.name": "العربية",
|
|
43
|
+
"dir": "rtl"
|
|
44
|
+
}
|
data/app/locales/cs.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"page.title_suffix": "Nastavení",
|
|
3
|
+
"page.brand_title": "SuperSettings",
|
|
4
|
+
"filter.label": "Filtr",
|
|
5
|
+
"filter.placeholder": "Filtrovat klíče",
|
|
6
|
+
"button.add_setting": "Přidat nastavení",
|
|
7
|
+
"button.discard_changes": "Zahodit změny",
|
|
8
|
+
"button.save": "Uložit",
|
|
9
|
+
"button.save_changes": "Změny",
|
|
10
|
+
"sort.label": "Seřadit podle:",
|
|
11
|
+
"sort.key": "Klíč",
|
|
12
|
+
"sort.modified": "Změněno",
|
|
13
|
+
"modal.close": "Zavřít dialog",
|
|
14
|
+
"card.key": "Klíč:",
|
|
15
|
+
"card.value": "Hodnota:",
|
|
16
|
+
"card.type": "Typ:",
|
|
17
|
+
"card.description": "Popis:",
|
|
18
|
+
"card.modified": "Změněno:",
|
|
19
|
+
"card.info_title": "Informace o nastavení",
|
|
20
|
+
"card.edit_title": "Upravit nastavení",
|
|
21
|
+
"card.remove_title": "Odebrat nastavení",
|
|
22
|
+
"card.cancel_title": "Zrušit změny",
|
|
23
|
+
"edit.key_placeholder": "Klíč nastavení",
|
|
24
|
+
"edit.description_placeholder": "Popis tohoto nastavení",
|
|
25
|
+
"edit.enabled": "Povoleno",
|
|
26
|
+
"edit.array_placeholder": "jeden záznam na řádek",
|
|
27
|
+
"edit.timezone_label": "Časové pásmo:",
|
|
28
|
+
"history.title": "Historie nastavení:",
|
|
29
|
+
"history.time": "Čas",
|
|
30
|
+
"history.changed_by": "Změnil(a)",
|
|
31
|
+
"history.value": "Hodnota",
|
|
32
|
+
"history.deleted": "smazáno",
|
|
33
|
+
"history.newer": "Novější",
|
|
34
|
+
"history.older": "Starší",
|
|
35
|
+
"count.setting": "Nastavení",
|
|
36
|
+
"count.settings": "Nastavení",
|
|
37
|
+
"prompt.unsaved": "Opravdu chcete odejít?",
|
|
38
|
+
"flash.saved": "Nastavení uložena",
|
|
39
|
+
"flash.save_failed": "Nepodařilo se uložit nastavení",
|
|
40
|
+
"error.generic": "Omlouváme se, došlo k chybě. Obnovte stránku a zkuste to znovu.",
|
|
41
|
+
"language.label": "Jazyk",
|
|
42
|
+
"language.name": "Čeština",
|
|
43
|
+
"dir": "ltr"
|
|
44
|
+
}
|
data/app/locales/da.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"page.title_suffix": "Indstillinger",
|
|
3
|
+
"page.brand_title": "SuperSettings",
|
|
4
|
+
"filter.label": "Filter",
|
|
5
|
+
"filter.placeholder": "Filternøgler",
|
|
6
|
+
"button.add_setting": "Tilføj indstilling",
|
|
7
|
+
"button.discard_changes": "Kassér ændringer",
|
|
8
|
+
"button.save": "Gem",
|
|
9
|
+
"button.save_changes": "Ændringer",
|
|
10
|
+
"sort.label": "Sortér efter:",
|
|
11
|
+
"sort.key": "Nøgle",
|
|
12
|
+
"sort.modified": "Ændret",
|
|
13
|
+
"modal.close": "Luk dialogboksen",
|
|
14
|
+
"card.key": "Nøgle:",
|
|
15
|
+
"card.value": "Værdi:",
|
|
16
|
+
"card.type": "Type:",
|
|
17
|
+
"card.description": "Beskrivelse:",
|
|
18
|
+
"card.modified": "Ændret:",
|
|
19
|
+
"card.info_title": "Indstillingsinfo",
|
|
20
|
+
"card.edit_title": "Rediger indstilling",
|
|
21
|
+
"card.remove_title": "Fjern indstilling",
|
|
22
|
+
"card.cancel_title": "Annuller ændringer",
|
|
23
|
+
"edit.key_placeholder": "Indstillingsnøgle",
|
|
24
|
+
"edit.description_placeholder": "Beskrivelse af denne indstilling",
|
|
25
|
+
"edit.enabled": "Aktiv",
|
|
26
|
+
"edit.array_placeholder": "én post pr. linje",
|
|
27
|
+
"edit.timezone_label": "Tidszone:",
|
|
28
|
+
"history.title": "Indstillingshistorik:",
|
|
29
|
+
"history.time": "Tid",
|
|
30
|
+
"history.changed_by": "Ændret af",
|
|
31
|
+
"history.value": "Værdi",
|
|
32
|
+
"history.deleted": "slettet",
|
|
33
|
+
"history.newer": "Nyere",
|
|
34
|
+
"history.older": "Ældre",
|
|
35
|
+
"count.setting": "Indstilling",
|
|
36
|
+
"count.settings": "Indstillinger",
|
|
37
|
+
"prompt.unsaved": "Er du sikker på, du vil forlade siden?",
|
|
38
|
+
"flash.saved": "Indstillinger gemt",
|
|
39
|
+
"flash.save_failed": "Kunne ikke gemme indstillinger",
|
|
40
|
+
"error.generic": "Beklager, der opstod en fejl. Opdater siden, og prøv igen.",
|
|
41
|
+
"language.label": "Sprog",
|
|
42
|
+
"language.name": "Dansk",
|
|
43
|
+
"dir": "ltr"
|
|
44
|
+
}
|
data/app/locales/de.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"page.title_suffix": "Einstellungen",
|
|
3
|
+
"page.brand_title": "SuperSettings",
|
|
4
|
+
"filter.label": "Filter",
|
|
5
|
+
"filter.placeholder": "Schlüssel filtern",
|
|
6
|
+
"button.add_setting": "Einstellung hinzufügen",
|
|
7
|
+
"button.discard_changes": "Änderungen verwerfen",
|
|
8
|
+
"button.save": "Speichern",
|
|
9
|
+
"button.save_changes": "Änderungen",
|
|
10
|
+
"sort.label": "Sortieren nach:",
|
|
11
|
+
"sort.key": "Schlüssel",
|
|
12
|
+
"sort.modified": "Geändert",
|
|
13
|
+
"modal.close": "Dialog schließen",
|
|
14
|
+
"card.key": "Schlüssel:",
|
|
15
|
+
"card.value": "Wert:",
|
|
16
|
+
"card.type": "Typ:",
|
|
17
|
+
"card.description": "Beschreibung:",
|
|
18
|
+
"card.modified": "Geändert:",
|
|
19
|
+
"card.info_title": "Einstellungsinfo",
|
|
20
|
+
"card.edit_title": "Einstellung bearbeiten",
|
|
21
|
+
"card.remove_title": "Einstellung entfernen",
|
|
22
|
+
"card.cancel_title": "Änderungen abbrechen",
|
|
23
|
+
"edit.key_placeholder": "Einstellungsschlüssel",
|
|
24
|
+
"edit.description_placeholder": "Beschreibung dieser Einstellung",
|
|
25
|
+
"edit.enabled": "Aktiviert",
|
|
26
|
+
"edit.array_placeholder": "ein Eintrag pro Zeile",
|
|
27
|
+
"edit.timezone_label": "Zeitzone:",
|
|
28
|
+
"history.title": "Einstellungsverlauf:",
|
|
29
|
+
"history.time": "Zeit",
|
|
30
|
+
"history.changed_by": "Geändert durch",
|
|
31
|
+
"history.value": "Wert",
|
|
32
|
+
"history.deleted": "gelöscht",
|
|
33
|
+
"history.newer": "Neuer",
|
|
34
|
+
"history.older": "Älter",
|
|
35
|
+
"count.setting": "Einstellung",
|
|
36
|
+
"count.settings": "Einstellungen",
|
|
37
|
+
"prompt.unsaved": "Möchten Sie die Seite wirklich verlassen?",
|
|
38
|
+
"flash.saved": "Einstellungen gespeichert",
|
|
39
|
+
"flash.save_failed": "Einstellungen konnten nicht gespeichert werden",
|
|
40
|
+
"error.generic": "Sorry, ein Fehler ist aufgetreten. Laden Sie die Seite neu und versuchen Sie es nochmal.",
|
|
41
|
+
"language.label": "Sprache",
|
|
42
|
+
"language.name": "Deutsch",
|
|
43
|
+
"dir": "ltr"
|
|
44
|
+
}
|
data/app/locales/el.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"page.title_suffix": "Ρυθμίσεις",
|
|
3
|
+
"page.brand_title": "SuperSettings",
|
|
4
|
+
"filter.label": "Φίλτρο",
|
|
5
|
+
"filter.placeholder": "Φιλτράρισμα Κλειδιών",
|
|
6
|
+
"button.add_setting": "Προσθήκη Ρύθμισης",
|
|
7
|
+
"button.discard_changes": "Απόρριψη Αλλαγών",
|
|
8
|
+
"button.save": "Αποθήκευση",
|
|
9
|
+
"button.save_changes": "Αλλαγές",
|
|
10
|
+
"sort.label": "Ταξινόμηση κατά:",
|
|
11
|
+
"sort.key": "Κλειδί",
|
|
12
|
+
"sort.modified": "Τροποποιήθηκε",
|
|
13
|
+
"modal.close": "Κλείσιμο Παραθύρου",
|
|
14
|
+
"card.key": "Κλειδί:",
|
|
15
|
+
"card.value": "Τιμή:",
|
|
16
|
+
"card.type": "Τύπος:",
|
|
17
|
+
"card.description": "Περιγραφή:",
|
|
18
|
+
"card.modified": "Τροποποιήθηκε:",
|
|
19
|
+
"card.info_title": "Πληροφορίες Ρύθμισης",
|
|
20
|
+
"card.edit_title": "Επεξεργασία Ρύθμισης",
|
|
21
|
+
"card.remove_title": "Αφαίρεση Ρύθμισης",
|
|
22
|
+
"card.cancel_title": "Ακύρωση Αλλαγών",
|
|
23
|
+
"edit.key_placeholder": "Κλειδί ρύθμισης",
|
|
24
|
+
"edit.description_placeholder": "Περιγραφή αυτής της ρύθμισης",
|
|
25
|
+
"edit.enabled": "Ενεργοποιημένο",
|
|
26
|
+
"edit.array_placeholder": "μία καταχώριση ανά γραμμή",
|
|
27
|
+
"edit.timezone_label": "Ζώνη Ώρας:",
|
|
28
|
+
"history.title": "Ιστορικό Ρυθμίσεων:",
|
|
29
|
+
"history.time": "Ώρα",
|
|
30
|
+
"history.changed_by": "Αλλαγή από",
|
|
31
|
+
"history.value": "Τιμή",
|
|
32
|
+
"history.deleted": "διαγράφηκε",
|
|
33
|
+
"history.newer": "Νεότερο",
|
|
34
|
+
"history.older": "Παλαιότερο",
|
|
35
|
+
"count.setting": "Ρύθμιση",
|
|
36
|
+
"count.settings": "Ρυθμίσεις",
|
|
37
|
+
"prompt.unsaved": "Είστε σίγουροι ότι θέλετε να φύγετε;",
|
|
38
|
+
"flash.saved": "Οι ρυθμίσεις αποθηκεύτηκαν",
|
|
39
|
+
"flash.save_failed": "Αποτυχία αποθήκευσης ρυθμίσεων",
|
|
40
|
+
"error.generic": "Συγγνώμη, προέκυψε σφάλμα. Ανανεώστε τη σελίδα και δοκιμάστε ξανά.",
|
|
41
|
+
"language.label": "Γλώσσα",
|
|
42
|
+
"language.name": "Ελληνικά",
|
|
43
|
+
"dir": "ltr"
|
|
44
|
+
}
|
data/app/locales/en.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"page.title_suffix": "Settings",
|
|
3
|
+
"page.brand_title": "SuperSettings",
|
|
4
|
+
|
|
5
|
+
"filter.label": "Filter",
|
|
6
|
+
"filter.placeholder": "Filter Keys",
|
|
7
|
+
|
|
8
|
+
"button.add_setting": "Add Setting",
|
|
9
|
+
"button.discard_changes": "Discard Changes",
|
|
10
|
+
"button.save": "Save",
|
|
11
|
+
"button.save_changes": "Changes",
|
|
12
|
+
|
|
13
|
+
"sort.label": "Sort by:",
|
|
14
|
+
"sort.key": "Key",
|
|
15
|
+
"sort.modified": "Modified",
|
|
16
|
+
|
|
17
|
+
"modal.close": "Close Dialog",
|
|
18
|
+
|
|
19
|
+
"card.key": "Key:",
|
|
20
|
+
"card.value": "Value:",
|
|
21
|
+
"card.type": "Type:",
|
|
22
|
+
"card.description": "Description:",
|
|
23
|
+
"card.modified": "Modified:",
|
|
24
|
+
"card.info_title": "Setting Info",
|
|
25
|
+
"card.edit_title": "Edit Setting",
|
|
26
|
+
"card.remove_title": "Remove Setting",
|
|
27
|
+
"card.cancel_title": "Cancel Changes",
|
|
28
|
+
|
|
29
|
+
"edit.key_placeholder": "Setting key",
|
|
30
|
+
"edit.description_placeholder": "Description of this setting",
|
|
31
|
+
"edit.enabled": "Enabled",
|
|
32
|
+
"edit.array_placeholder": "one entry per line",
|
|
33
|
+
"edit.timezone_label": "Time Zone:",
|
|
34
|
+
|
|
35
|
+
"history.title": "Setting History:",
|
|
36
|
+
"history.time": "Time",
|
|
37
|
+
"history.changed_by": "Changed By",
|
|
38
|
+
"history.value": "Value",
|
|
39
|
+
"history.deleted": "deleted",
|
|
40
|
+
"history.newer": "Newer",
|
|
41
|
+
"history.older": "Older",
|
|
42
|
+
|
|
43
|
+
"count.setting": "Setting",
|
|
44
|
+
"count.settings": "Settings",
|
|
45
|
+
"prompt.unsaved": "Are you sure you want to leave?",
|
|
46
|
+
"flash.saved": "Settings saved",
|
|
47
|
+
"flash.save_failed": "Failed to save settings",
|
|
48
|
+
|
|
49
|
+
"error.generic": "Sorry, an error occurred. Refresh the page and try again.",
|
|
50
|
+
|
|
51
|
+
"language.label": "Language",
|
|
52
|
+
"language.name": "English",
|
|
53
|
+
|
|
54
|
+
"dir": "ltr"
|
|
55
|
+
}
|