vario 0.4.12
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +61 -0
- data/Rakefile +37 -0
- data/app/controllers/vario/application_controller.rb +15 -0
- data/app/controllers/vario/levels_controller.rb +63 -0
- data/app/controllers/vario/settings_controller.rb +35 -0
- data/app/helpers/vario/application_helper.rb +13 -0
- data/app/jobs/vario/application_job.rb +4 -0
- data/app/mailers/vario/application_mailer.rb +6 -0
- data/app/models/vario/application_record.rb +5 -0
- data/app/models/vario/condition.rb +39 -0
- data/app/models/vario/level.rb +94 -0
- data/app/models/vario/setting.rb +188 -0
- data/app/views/vario/levels/_form.html.slim +53 -0
- data/app/views/vario/levels/create.js.erb +4 -0
- data/app/views/vario/levels/destroy.js.erb +4 -0
- data/app/views/vario/levels/update.js.erb +4 -0
- data/app/views/vario/settings/_levels.html.slim +22 -0
- data/app/views/vario/settings/_new_level.html.slim +7 -0
- data/app/views/vario/settings/_settings.html.slim +30 -0
- data/app/views/vario/settings/index.html.slim +28 -0
- data/app/views/vario/settings/levels.html.slim +1 -0
- data/app/views/vario/settings/show.html.slim +13 -0
- data/config/locales/en.yml +6 -0
- data/config/locales/nl.yml +6 -0
- data/config/routes.rb +10 -0
- data/db/migrate/20180628103728_create_vario_settings.rb +20 -0
- data/db/migrate/20180706130136_remove_fields_from_settings.rb +7 -0
- data/db/migrate/20180706155055_add_keys_to_setting.rb +5 -0
- data/db/migrate/20211027040546_unique_levels.rb +8 -0
- data/lib/vario/action_view_helpers.rb +31 -0
- data/lib/vario/active_record_helpers.rb +23 -0
- data/lib/vario/api.rb +148 -0
- data/lib/vario/config.rb +112 -0
- data/lib/vario/engine.rb +15 -0
- data/lib/vario/settable.rb +44 -0
- data/lib/vario/settings_reader.rb +35 -0
- data/lib/vario/version.rb +5 -0
- data/lib/vario.rb +30 -0
- metadata +194 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5e58ac2e2f8d599f2c079997d4a1aff97eab6f942d3defabf2be5e761fbd153c
|
4
|
+
data.tar.gz: 38b17c68f3d33f8c6244761249831457cb7c2e1d0659128b54bb65140ca82947
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 18dac0cfad4d0e2d4dce4dc8cde21163fa068bb4f2f6c26db0eb87d040477f12eb8eb9a02716bab740a729ba0e300634994aef06512cf36a644b05f520059cf9
|
7
|
+
data.tar.gz: 4fbdb499f8cb06c0ccc1e419efe323e7ee1b538495822762aff7c10d1c94ca9bc3fe046676d3b9927c44e04b0363b3e48757b244226e59a8cf03a342195fd908
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018 Andre Meij
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Vario
|
2
|
+
|
3
|
+
Vario allows configuration over multiple levels and tied to different objects. It is a simple and flexible way to configure your project.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
Add the vario.rb initializer to your project and configure it.
|
8
|
+
Say your way to separate tenants is using an Account model, you would make 'Account' the settable and you can configure settings on it:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
Vario.setup do |config|
|
12
|
+
config.key :environment, name: 'Environment', type: :select, collection_proc: -> { [%w[Production production], %w[Test test], %w[Development development]] }, value_proc: -> { Rails.env }
|
13
|
+
|
14
|
+
config.for_settable_type 'Account' do |settable|
|
15
|
+
settable.raise_on_undefined true
|
16
|
+
|
17
|
+
settable.setting 'internationalization.default_currency', type: :string, default: 'USD', description: 'Default currency for new products.', collection_proc: -> { Money::Currency.map { |currency| ["#{currency.iso_code} - #{currency.name}", currency.iso_code] }.sort }
|
18
|
+
settable.setting 'internationalization.week_start', type: :symbol, default: :monday, description: 'First day of the week', collection: [['Monday', :monday], ['Tuesday', :tuesday], ['Wednesday', :wednesday], ['Thursday', :thursday], ['Friday', :friday], ['Saturday', :saturday], ['Sunday', :sunday]]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
Next add vario to your routes.rb:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
mount Vario::Engine, at: "/settings", as: "vario"
|
27
|
+
```
|
28
|
+
|
29
|
+
Then add a menu entry, or link to the settings page:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
link_to("Settings", vario.settings_path(settable: Current&.account&.to_sgid(for: "Vario").to_s))
|
33
|
+
```
|
34
|
+
|
35
|
+
## Installation
|
36
|
+
|
37
|
+
Add this line to your application's Gemfile:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
gem 'vario'
|
41
|
+
```
|
42
|
+
|
43
|
+
And then execute:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
$ bundle
|
47
|
+
```
|
48
|
+
|
49
|
+
Or install it yourself as:
|
50
|
+
|
51
|
+
```bash
|
52
|
+
$ gem install vario
|
53
|
+
```
|
54
|
+
|
55
|
+
## Contributing
|
56
|
+
|
57
|
+
Contribution directions go here.
|
58
|
+
|
59
|
+
## License
|
60
|
+
|
61
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Vario'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
load 'rails/tasks/statistics.rake'
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = 'test/**/*_test.rb'
|
29
|
+
t.verbose = false
|
30
|
+
t.warning = false
|
31
|
+
end
|
32
|
+
|
33
|
+
task default: :test
|
34
|
+
|
35
|
+
# Adds the Auxilium semver task
|
36
|
+
spec = Gem::Specification.find_by_name 'auxilium'
|
37
|
+
load "#{spec.gem_dir}/lib/tasks/semver.rake"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Vario
|
2
|
+
class ApplicationController < Vario.config.base_controller.constantize
|
3
|
+
protect_from_forgery with: :exception
|
4
|
+
|
5
|
+
layout Vario.config.admin_layout
|
6
|
+
|
7
|
+
def add_breadcrumbs(*args)
|
8
|
+
method(:add_breadcrumbs).super_method&.call(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def breadcrumb_settings_path(setting, options = {})
|
12
|
+
settings_path(options.merge(settable: setting.settable.to_sgid(for: 'Vario').to_s))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_dependency 'vario/application_controller'
|
2
|
+
|
3
|
+
module Vario
|
4
|
+
class LevelsController < ApplicationController
|
5
|
+
self.responder = Auxilium::Responder
|
6
|
+
respond_to :html, :js
|
7
|
+
|
8
|
+
before_action :set_objects
|
9
|
+
|
10
|
+
def create
|
11
|
+
@level = Level.new(@setting, level_params)
|
12
|
+
@setting.levels.unshift @level
|
13
|
+
@setting.save
|
14
|
+
|
15
|
+
respond_with @setting, collection_location: setting_path(@setting)
|
16
|
+
end
|
17
|
+
|
18
|
+
def update
|
19
|
+
if params[:commit] == 'delete'
|
20
|
+
self.action_name = 'destroy'
|
21
|
+
return destroy
|
22
|
+
end
|
23
|
+
|
24
|
+
@level = @setting.levels.find { |level| level.id == params[:id] }
|
25
|
+
@level.value = level_params[:value]
|
26
|
+
@level.conditions = level_params[:conditions].to_h
|
27
|
+
@setting.save
|
28
|
+
|
29
|
+
respond_with @setting, collection_location: setting_path(@setting)
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy
|
33
|
+
@setting.levels.reject! { |level| level.id == params[:id] }
|
34
|
+
@setting.save
|
35
|
+
|
36
|
+
respond_with @setting, collection_location: setting_path(@setting)
|
37
|
+
end
|
38
|
+
|
39
|
+
def move
|
40
|
+
oldIndex = @setting.levels.find_index { |level| level.id == params[:id] }
|
41
|
+
newIndex = params[:index]
|
42
|
+
@level = @setting.levels[oldIndex]
|
43
|
+
@level.move(oldIndex - newIndex)
|
44
|
+
|
45
|
+
render json: { old: oldIndex, new: newIndex }
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def set_objects
|
51
|
+
@context = params.dig(:level, :context) || {}
|
52
|
+
@setting = Setting.find(params[:setting_id])
|
53
|
+
if respond_to? :add_breadcrumb
|
54
|
+
add_breadcrumb I18n.t('breadcrumbs.vario.settings.index'), breadcrumb_settings_path(@setting)
|
55
|
+
add_breadcrumb @setting.name, setting_path(@setting)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def level_params
|
60
|
+
params.require(:level).permit(:value, value: [], conditions: {}, context: {})
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_dependency 'vario/application_controller'
|
2
|
+
|
3
|
+
module Vario
|
4
|
+
class SettingsController < ApplicationController
|
5
|
+
def index
|
6
|
+
if respond_to?(:add_breadcrumb)
|
7
|
+
add_breadcrumb I18n.t('breadcrumbs.vario.settings.index'), settings_path(settable: params[:settable])
|
8
|
+
end
|
9
|
+
|
10
|
+
@settable = GlobalID::Locator.locate_signed(params[:settable], for: 'Vario')
|
11
|
+
@title = 'Settings'
|
12
|
+
@title = "#{@title} for #{@settable.class.name} #{@settable.name}" if @settable.respond_to?(:name)
|
13
|
+
Vario.config.pre_create_settings(@settable)
|
14
|
+
|
15
|
+
@settings = Setting.where(settable: @settable).order(:name).includes(:settable)
|
16
|
+
@groups = @settings.map(&:name).select { |setting| setting =~ /\./ }.map { |setting| setting.split('.').first }
|
17
|
+
@groups = @groups.find_all { |g| Vario.config.show_group?(g) }
|
18
|
+
@groups = @groups.each_with_object(Hash.new(0)) { |v, h| h[v] += 1; }.map { |k, v| { name: k, settings: v } }
|
19
|
+
end
|
20
|
+
|
21
|
+
def show
|
22
|
+
@setting = Setting.find(params[:id])
|
23
|
+
|
24
|
+
if respond_to?(:add_breadcrumb)
|
25
|
+
add_breadcrumb I18n.t('breadcrumbs.vario.settings.index'), breadcrumb_settings_path(@setting)
|
26
|
+
add_breadcrumb @setting.name, setting_path(@setting)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def levels
|
31
|
+
@setting = Setting.find(params[:id])
|
32
|
+
render :levels, layout: false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vario
|
4
|
+
class Condition
|
5
|
+
include ActiveModel::Model
|
6
|
+
attr_accessor :key, :value
|
7
|
+
|
8
|
+
def initialize(setting, key, value)
|
9
|
+
@setting = setting
|
10
|
+
@key = key
|
11
|
+
@value = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def human_value
|
15
|
+
if key_data[:type] == :select
|
16
|
+
collection.find { |entry| entry.last == value }.first
|
17
|
+
else
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def key_data
|
23
|
+
Vario.config.key_data_for(key)
|
24
|
+
end
|
25
|
+
|
26
|
+
def collection
|
27
|
+
return @collection if @collection
|
28
|
+
|
29
|
+
@collection = key_data[:collection]
|
30
|
+
@collection ||= instance_exec(&key_data[:collection_proc]) if key_data[:collection_proc]
|
31
|
+
@collection ||= []
|
32
|
+
if value.present?
|
33
|
+
current_value = @collection.find { |entry| entry.last == value }
|
34
|
+
@collection << ["<#{value}>", value] unless current_value
|
35
|
+
end
|
36
|
+
@collection
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vario
|
4
|
+
class Level
|
5
|
+
include ActiveModel::Model
|
6
|
+
attr_reader :conditions
|
7
|
+
attr_accessor :id, :setting, :value
|
8
|
+
|
9
|
+
def initialize(setting, level, new_record = false)
|
10
|
+
level = level.to_h.with_indifferent_access
|
11
|
+
@setting = setting
|
12
|
+
@id = level[:id] || SecureRandom.hex
|
13
|
+
@value = level[:value]
|
14
|
+
@new_record = new_record
|
15
|
+
self.conditions = level[:conditions]
|
16
|
+
end
|
17
|
+
|
18
|
+
def conditions=(new_conditions)
|
19
|
+
new_conditions = (new_conditions || {}).with_indifferent_access
|
20
|
+
@conditions = setting.keys.map do |key|
|
21
|
+
Condition.new(setting, key, new_conditions[key])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def conditions_for(context)
|
26
|
+
conditions.select { |condition| context.key?(condition.key.to_sym) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def conditions_not_for(context)
|
30
|
+
conditions.reject { |condition| context.key?(condition.key.to_sym) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_conditions
|
34
|
+
conditions.reject { |condition| condition.value.blank? }
|
35
|
+
end
|
36
|
+
|
37
|
+
def conditions_hash
|
38
|
+
set_conditions.map { |c| [c.key.to_sym, c.value] }.to_h
|
39
|
+
end
|
40
|
+
|
41
|
+
def with_context_values?(context)
|
42
|
+
context.each do |key, value|
|
43
|
+
condition = conditions.find { |condition| condition.key == key.to_s }
|
44
|
+
return false if condition.value != value
|
45
|
+
end
|
46
|
+
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def move(positions)
|
51
|
+
if positions.positive?
|
52
|
+
move_up(positions)
|
53
|
+
else
|
54
|
+
move_down(positions.abs)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def move_up(positions = 1)
|
59
|
+
positions.times { |time| setting.move_level_up(self) }
|
60
|
+
setting.save!
|
61
|
+
end
|
62
|
+
|
63
|
+
def move_down(positions = 1)
|
64
|
+
positions.times { |time| setting.move_level_down(self) }
|
65
|
+
setting.save!
|
66
|
+
end
|
67
|
+
|
68
|
+
def human_value
|
69
|
+
hv = setting.human_value(value)
|
70
|
+
return unless hv
|
71
|
+
setting.type == :array ? hv.join(', ') : hv.to_s
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_h
|
75
|
+
{
|
76
|
+
id: id,
|
77
|
+
conditions: conditions_hash,
|
78
|
+
value: value
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def value_present?
|
83
|
+
value === false || value.present?
|
84
|
+
end
|
85
|
+
|
86
|
+
def default?
|
87
|
+
set_conditions.size.zero?
|
88
|
+
end
|
89
|
+
|
90
|
+
def persisted?
|
91
|
+
!@new_record
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Vario
|
4
|
+
class Setting < ApplicationRecord
|
5
|
+
attr_reader :settable_setting, :type, :default, :description
|
6
|
+
|
7
|
+
has_paper_trail if respond_to?(:has_paper_trail)
|
8
|
+
|
9
|
+
belongs_to :settable, polymorphic: true, optional: true
|
10
|
+
validates :name, uniqueness: { scope: %i[settable_type settable_id] }
|
11
|
+
validate :validate_levels
|
12
|
+
|
13
|
+
after_initialize :configure, :levels # pre-init the levels
|
14
|
+
before_save :update_level_data
|
15
|
+
|
16
|
+
scope :for_group, ->(group_name) { where('name ilike ?', "#{group_name}.%") }
|
17
|
+
scope :without_group, -> { where.not('name ilike ?', "%.%") }
|
18
|
+
|
19
|
+
def group_name
|
20
|
+
return nil if name.blank?
|
21
|
+
|
22
|
+
parts = name.split('.', 2)
|
23
|
+
|
24
|
+
return nil if parts.size == 1
|
25
|
+
|
26
|
+
parts.first
|
27
|
+
end
|
28
|
+
|
29
|
+
def setting_name
|
30
|
+
return name if name.blank?
|
31
|
+
|
32
|
+
name.split('.', 2).last || name
|
33
|
+
end
|
34
|
+
|
35
|
+
def title
|
36
|
+
return "#{group_name.humanize}: #{setting_name.humanize}" if group_name.present?
|
37
|
+
|
38
|
+
setting_name.humanize if setting_name.present?
|
39
|
+
end
|
40
|
+
|
41
|
+
def value_for(context)
|
42
|
+
current_default = context.delete(:default)
|
43
|
+
|
44
|
+
unless initialized?
|
45
|
+
raise UnknownSetting, "Configuration key '#{name}' not initialized for #{settable_type}" if Vario.config.raise_on_undefined?(settable_type)
|
46
|
+
return current_default unless Vario.config.create_on_request?(settable_type)
|
47
|
+
|
48
|
+
# This is a new record, save it to the table since create_on_request? is true
|
49
|
+
self.keys = Vario.config.default_keys?(settable_type)
|
50
|
+
self.levels << Vario::Level.new(self, conditions: {}, value: current_default)
|
51
|
+
end
|
52
|
+
|
53
|
+
context = context.symbolize_keys
|
54
|
+
update_context(context)
|
55
|
+
validate_context(context)
|
56
|
+
|
57
|
+
result = levels.find do |level|
|
58
|
+
context >= level.conditions_hash
|
59
|
+
end
|
60
|
+
|
61
|
+
return parse_value(result.value) if result.present? && result.value_present?
|
62
|
+
|
63
|
+
parse_value(current_default || default)
|
64
|
+
end
|
65
|
+
|
66
|
+
def configure
|
67
|
+
self.keys ||= []
|
68
|
+
|
69
|
+
@settable_setting = Vario.config.settable_setting(settable_type, name)
|
70
|
+
return unless settable_setting
|
71
|
+
|
72
|
+
@type = settable_setting[:type]
|
73
|
+
self.keys = settable_setting[:keys]
|
74
|
+
@default = settable_setting[:default]
|
75
|
+
@description = settable_setting[:description]
|
76
|
+
end
|
77
|
+
|
78
|
+
def levels
|
79
|
+
@levels ||= (attributes['levels'] || []).map { |level| Level.new(self, level) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def uniq_levels
|
83
|
+
selected = []
|
84
|
+
|
85
|
+
levels.each do |level|
|
86
|
+
next if selected.select { |uniq_level| uniq_level.conditions_hash == level.conditions_hash}.present?
|
87
|
+
|
88
|
+
selected << level
|
89
|
+
end
|
90
|
+
|
91
|
+
selected
|
92
|
+
end
|
93
|
+
|
94
|
+
def uniq_levels!
|
95
|
+
self.levels = uniq_levels.select { |l| l.value_present? }.map(&:to_h)
|
96
|
+
@levels = nil
|
97
|
+
save!
|
98
|
+
end
|
99
|
+
|
100
|
+
def update_level_data
|
101
|
+
self.levels = levels.select { |l| l.value_present? }.map(&:to_h)
|
102
|
+
end
|
103
|
+
|
104
|
+
def move_level_up(level)
|
105
|
+
index = levels.index(level)
|
106
|
+
level = levels.delete(level)
|
107
|
+
levels.insert(index - 1, level)
|
108
|
+
end
|
109
|
+
|
110
|
+
def move_level_down(level)
|
111
|
+
index = levels.index(level)
|
112
|
+
level = levels.delete(level)
|
113
|
+
levels.insert(index + 1, level)
|
114
|
+
end
|
115
|
+
|
116
|
+
def initialized?
|
117
|
+
return false if Vario.config.raise_on_undefined?(settable) && !persisted?
|
118
|
+
settable_setting.present? || persisted?
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse_value(value)
|
122
|
+
return false if [0, '0', 'false', '', false].include?(value) && type == :boolean
|
123
|
+
return true if [1, '1', 'true', true].include?(value) && type == :boolean
|
124
|
+
return unless value.present?
|
125
|
+
return parse_value_array(value) if type == :array
|
126
|
+
return value unless value.is_a?(String)
|
127
|
+
return YAML.load(value) if type == :hash
|
128
|
+
return value.to_i if type == :integer
|
129
|
+
|
130
|
+
value
|
131
|
+
end
|
132
|
+
|
133
|
+
def human_value(value)
|
134
|
+
parsed_value = parse_value(value)
|
135
|
+
return parsed_value if collection.blank?
|
136
|
+
return parsed_value.map { |pv| collection.find { |i| i.last == pv }.first } if type == :array
|
137
|
+
|
138
|
+
collection.find { |i| i.last == parsed_value }.first
|
139
|
+
end
|
140
|
+
|
141
|
+
def parse_value_array(value)
|
142
|
+
values = value
|
143
|
+
values = values.split(/,|\n/).map(&:strip) if values.is_a?(String)
|
144
|
+
values = values.reject(&:blank?)
|
145
|
+
|
146
|
+
# If a collection has been defined, and 'all' is in the selected values, return all id's from the colletion
|
147
|
+
return collection.map(&:last) if (values.include?('all') || values.include?(:all)) && collection
|
148
|
+
|
149
|
+
values
|
150
|
+
end
|
151
|
+
|
152
|
+
def collection
|
153
|
+
return @collection if @collection
|
154
|
+
return unless settable_setting
|
155
|
+
|
156
|
+
@collection = settable_setting[:collection]
|
157
|
+
@collection ||= instance_exec(&settable_setting[:collection_proc]) if settable_setting[:collection_proc]
|
158
|
+
@collection ||= []
|
159
|
+
@collection
|
160
|
+
end
|
161
|
+
|
162
|
+
def new_level
|
163
|
+
Level.new(self, {}, true)
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
###
|
169
|
+
# Fill blank values for which we've got a value_proc
|
170
|
+
#
|
171
|
+
def update_context(context)
|
172
|
+
keys.each do |key|
|
173
|
+
key = key.to_sym
|
174
|
+
key_data = Vario.config.key_data_for(key)
|
175
|
+
context[key] ||= instance_exec(&key_data[:value_proc]) if key_data.key?(:value_proc)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def validate_context(context)
|
180
|
+
missing = keys.map(&:to_sym) - context.keys
|
181
|
+
raise ArgumentError, "missing context '#{missing.join(', ')}''" if missing.present?
|
182
|
+
end
|
183
|
+
|
184
|
+
def validate_levels
|
185
|
+
errors.add(:levels, I18n.t('errors.messages.taken')) if levels.map(&:conditions_hash).uniq.size != levels.size
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
- label = nil if label.blank?
|
2
|
+
- context = {} if context.blank?
|
3
|
+
- draggable = true if draggable.nil?
|
4
|
+
|
5
|
+
= sts.form_for([setting, level], id: level.id, url: polymorphic_path([vario, setting, level]), remote: true, title: label, footer: false, header: label.present?, padding: label.present?) do |f|
|
6
|
+
- context.each do |key, value|
|
7
|
+
= f.fields_for :context do |ff|
|
8
|
+
= ff.input key, as: :hidden, input_html: { value: value }
|
9
|
+
- level.conditions_for(context).each do |condition|
|
10
|
+
= f.fields_for :conditions do |ff|
|
11
|
+
= ff.input condition.key, as: :hidden, input_html: { value: context[condition.key.to_sym] }
|
12
|
+
.grid.grid-cols-12.gap-4
|
13
|
+
.col-span-1
|
14
|
+
- if draggable
|
15
|
+
button.draggable
|
16
|
+
i class="fal fa-grip-lines" style="margin-top: 8px; margin-left: 16px;"
|
17
|
+
.col-span-7
|
18
|
+
.grid.grid-cols-12.gap-4
|
19
|
+
- level.conditions_not_for(context).each do |condition|
|
20
|
+
div class="col-span-#{[12 / level.conditions_not_for(context).size, 3].max}"
|
21
|
+
= f.fields_for :conditions do |ff|
|
22
|
+
- case condition.key_data[:type]
|
23
|
+
- when :select
|
24
|
+
= ff.input condition.key, as: :dropdown, label: condition.key, collection: condition.collection, include_blank: true, required: false, input_html: { id: "#{condition.key}_#{level.id}", value: condition.value }
|
25
|
+
- when :boolean
|
26
|
+
= ff.input condition.key, as: :switch, label: condition.key, value: condition.value, required: false
|
27
|
+
- else
|
28
|
+
= ff.input condition.key, label: condition.key, required: false, input_html: { value: context[condition.key.to_sym] }
|
29
|
+
|
30
|
+
.col-span-2
|
31
|
+
- case setting.type
|
32
|
+
- when :array
|
33
|
+
- if setting.collection.present?
|
34
|
+
= f.input :value, as: :select, input_html: { multiple: true, id: "value_#{level.id}" }, collection: [["All", 'all']] + setting.collection, required: false
|
35
|
+
- else
|
36
|
+
= f.input :value, as: :text, input_html: { rows: 10, style: 'height: auto' }, hint: 'Multiple values possible, separate with "," or new lines.'
|
37
|
+
- when :integer
|
38
|
+
= f.input :value, as: :number
|
39
|
+
- when :boolean
|
40
|
+
= f.input :value, as: :switch
|
41
|
+
- when :text
|
42
|
+
= f.input :value, as: :editor, mode: 'text/plain'
|
43
|
+
- when :hash
|
44
|
+
= f.input :value, as: :editor, mode: 'application/yaml'
|
45
|
+
- else
|
46
|
+
- if setting.collection.present?
|
47
|
+
= f.input :value, as: :dropdown, collection: setting.collection, required: false
|
48
|
+
- else
|
49
|
+
= f.input :value
|
50
|
+
.col-span-1.p-3
|
51
|
+
= f.button t('.save'), value: 'save'
|
52
|
+
.col-span-1.p-3
|
53
|
+
= f.button t('.delete'), value: 'delete' unless label.present?
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<% if @setting.saved_changes? %>
|
2
|
+
document.querySelector("[data-id='<%= @setting.id %>_levels']").innerHTML = "<%= escape_javascript(render(partial: 'vario/settings/levels', locals: { setting: @setting, context: @context })) %>"
|
3
|
+
document.querySelector("[data-id='<%= @setting.id %>_new_level']").innerHTML = "<%= escape_javascript(render(partial: 'vario/settings/new_level', locals: { setting: @setting, context: @context })) %>"
|
4
|
+
<% end %>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<% if @setting.saved_changes? %>
|
2
|
+
document.querySelector("[data-id='<%= @setting.id %>_levels']").innerHTML = "<%= escape_javascript(render(partial: 'vario/settings/levels', locals: { setting: @setting, context: @context })) %>"
|
3
|
+
document.querySelector("[data-id='<%= @setting.id %>_new_level']").innerHTML = "<%= escape_javascript(render(partial: 'vario/settings/new_level', locals: { setting: @setting, context: @context })) %>"
|
4
|
+
<% end %>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<% if @setting.saved_changes? %>
|
2
|
+
document.querySelector("[data-id='<%= @setting.id %>_levels']").innerHTML = "<%= escape_javascript(render(partial: 'vario/settings/levels', locals: { setting: @setting, context: @context })) %>"
|
3
|
+
document.querySelector("[data-id='<%= @setting.id %>_new_level']").innerHTML = "<%= escape_javascript(render(partial: 'vario/settings/new_level', locals: { setting: @setting, context: @context })) %>"
|
4
|
+
<% end %>
|