ab_admin 0.8.3 → 0.10.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.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +11 -5
  4. data/app/assets/javascripts/ab_admin/components/admin_assets.js.coffee +0 -25
  5. data/app/assets/javascripts/ab_admin/components/google_translate.js.coffee +3 -5
  6. data/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +33 -25
  7. data/app/assets/javascripts/ab_admin/core/batch_actions.js.coffee +1 -1
  8. data/app/assets/javascripts/ab_admin/core/columns_hider.js.coffee +24 -23
  9. data/app/assets/javascripts/ab_admin/core/init.js.coffee +7 -2
  10. data/app/assets/javascripts/ab_admin/core/search_form.js.coffee +1 -7
  11. data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +23 -7
  12. data/app/assets/javascripts/ab_admin/core/utils.js.coffee +16 -2
  13. data/app/assets/javascripts/ab_admin/inputs/datetime_input.js.coffee +1 -0
  14. data/app/assets/javascripts/ab_admin/main.js +3 -4
  15. data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.scss +71 -25
  16. data/app/assets/stylesheets/ab_admin/components/_base.scss +21 -1
  17. data/app/assets/stylesheets/ab_admin/components/_colored_tabs.scss +1 -1
  18. data/app/assets/stylesheets/ab_admin/components/_form.scss +16 -18
  19. data/app/assets/stylesheets/ab_admin/components/_grid_view.scss +2 -2
  20. data/app/assets/stylesheets/ab_admin/components/_locale_tabs.scss +11 -23
  21. data/app/assets/stylesheets/ab_admin/components/_navigation.scss +7 -11
  22. data/app/assets/stylesheets/ab_admin/components/_table_view.scss +85 -11
  23. data/app/assets/stylesheets/ab_admin/components/_tooltip.scss +81 -0
  24. data/app/assets/stylesheets/ab_admin/components/_tree_view.scss +1 -1
  25. data/app/assets/stylesheets/ab_admin/devise.scss +2 -2
  26. data/app/assets/stylesheets/ab_admin/fileupload.scss +2 -9
  27. data/app/assets/stylesheets/ab_admin/main.scss +1 -2
  28. data/app/controllers/admin/assets_controller.rb +1 -1
  29. data/app/controllers/admin/base_controller.rb +133 -149
  30. data/app/controllers/admin/dashboards_controller.rb +2 -2
  31. data/app/controllers/admin/locators_controller.rb +8 -6
  32. data/app/controllers/admin/manager_controller.rb +19 -49
  33. data/app/controllers/admin/static_pages_controller.rb +0 -4
  34. data/app/controllers/admin/structures_controller.rb +2 -2
  35. data/app/views/ab_admin/devise/sessions/new.html.slim +2 -0
  36. data/app/views/admin/assets/batch_edit.html.slim +3 -2
  37. data/app/views/admin/base/_search_layout.html.slim +7 -6
  38. data/app/views/admin/base/create.js.erb +6 -3
  39. data/app/views/admin/base/edit.js.erb +1 -1
  40. data/app/views/admin/base/index.html.slim +4 -4
  41. data/app/views/admin/base/new.js.erb +1 -1
  42. data/app/views/admin/base/update.js.erb +7 -2
  43. data/app/views/admin/fileupload/_asset_templates.html.slim +1 -2
  44. data/app/views/admin/fileupload/_image.html.slim +1 -2
  45. data/app/views/admin/locators/edit.html.slim +7 -6
  46. data/app/views/admin/manager/_map.html.slim +4 -0
  47. data/app/views/admin/manager/_show_table.html.slim +1 -1
  48. data/app/views/admin/manager/_stats.html.slim +4 -0
  49. data/app/views/admin/manager/_table.html.slim +7 -4
  50. data/app/views/admin/shared/_content_actions.html.slim +35 -30
  51. data/app/views/admin/shared/_flash.html.slim +5 -4
  52. data/app/views/admin/shared/_locale_tabs.html.slim +2 -2
  53. data/app/views/admin/shared/_main_menu.html.slim +1 -1
  54. data/app/views/admin/shared/_save_buttons.html.slim +10 -1
  55. data/app/views/admin/structures/_form.html.slim +1 -1
  56. data/app/views/admin/users/_form.html.slim +3 -3
  57. data/app/views/admin/users/_search_form.html.slim +1 -1
  58. data/app/views/layouts/admin/_footer.html.slim +0 -1
  59. data/app/views/layouts/admin/_navigation.html.slim +1 -1
  60. data/app/views/layouts/admin/application.html.slim +2 -2
  61. data/config/locales/de.yml +1 -2
  62. data/config/locales/en.yml +9 -15
  63. data/config/locales/it.yml +1 -0
  64. data/config/locales/ru.yml +0 -1
  65. data/config/locales/uk.yml +0 -1
  66. data/db/migrate/20130101000001_create_users.rb +1 -4
  67. data/db/migrate/20130101000003_create_assets.rb +1 -1
  68. data/db/migrate/20130101000004_create_headers.rb +5 -5
  69. data/db/migrate/20130101000005_create_static_pages.rb +2 -5
  70. data/db/migrate/20130101000006_create_structures.rb +1 -1
  71. data/db/migrate/20130101000007_base_translations.rb +43 -12
  72. data/db/migrate/20130101000008_create_admin_comments.rb +2 -7
  73. data/db/migrate/20130101000009_create_tracks.rb +4 -8
  74. data/lib/ab_admin/abstract_resource.rb +6 -5
  75. data/lib/ab_admin/carrierwave/base_uploader.rb +87 -75
  76. data/lib/ab_admin/carrierwave/glue.rb +0 -5
  77. data/lib/ab_admin/concerns/admin_addition.rb +15 -27
  78. data/lib/ab_admin/concerns/translations_macro.rb +97 -0
  79. data/lib/ab_admin/concerns/utilities.rb +2 -2
  80. data/lib/ab_admin/config/base.rb +27 -4
  81. data/lib/ab_admin/controllers/callbacks.rb +3 -26
  82. data/lib/ab_admin/core_ext/array.rb +1 -50
  83. data/lib/ab_admin/core_ext/hash.rb +2 -31
  84. data/lib/ab_admin/core_ext/other.rb +0 -6
  85. data/lib/ab_admin/core_ext/string.rb +1 -86
  86. data/lib/ab_admin/devise.rb +7 -0
  87. data/lib/ab_admin/engine.rb +2 -1
  88. data/lib/ab_admin/hooks/ckeditor_lazy.rb +13 -0
  89. data/lib/ab_admin/hooks/will_paginate_id_prefetch.rb +8 -6
  90. data/lib/ab_admin/hooks/will_paginate_no_uri.rb +1 -1
  91. data/lib/ab_admin/i18n_tools/google_translate.rb +3 -1
  92. data/lib/ab_admin/i18n_tools/model_translator.rb +1 -1
  93. data/lib/ab_admin/menu/base_group.rb +0 -1
  94. data/lib/ab_admin/menu/group.rb +2 -4
  95. data/lib/ab_admin/menu/item.rb +4 -8
  96. data/lib/ab_admin/models/asset.rb +7 -10
  97. data/lib/ab_admin/models/header.rb +2 -2
  98. data/lib/ab_admin/models/locator.rb +29 -3
  99. data/lib/ab_admin/models/settings.rb +2 -2
  100. data/lib/ab_admin/models/structure.rb +3 -3
  101. data/lib/ab_admin/models/track.rb +15 -3
  102. data/lib/ab_admin/models/user.rb +12 -48
  103. data/lib/ab_admin/utils/csv_document.rb +8 -6
  104. data/lib/ab_admin/utils/eval_helpers.rb +0 -13
  105. data/lib/ab_admin/utils/logger.rb +12 -2
  106. data/lib/ab_admin/utils/mysql.rb +2 -3
  107. data/lib/ab_admin/utils/xls_document.rb +18 -18
  108. data/lib/ab_admin/utils.rb +0 -5
  109. data/lib/ab_admin/version.rb +1 -1
  110. data/lib/ab_admin/views/admin_helpers.rb +43 -28
  111. data/lib/ab_admin/views/admin_navigation_helpers.rb +18 -16
  112. data/lib/ab_admin/views/form_builder.rb +7 -5
  113. data/lib/ab_admin/views/helpers.rb +0 -9
  114. data/lib/ab_admin/views/inputs/ckeditor_input.rb +1 -5
  115. data/lib/ab_admin/views/manager_helpers.rb +15 -6
  116. data/lib/ab_admin/views/search_form_builder.rb +13 -13
  117. data/lib/ab_admin/views/will_paginate_bootstrap_renderer.rb +60 -0
  118. data/lib/ab_admin.rb +44 -32
  119. data/lib/generators/ab_admin/glob/glob_generator.rb +4 -5
  120. data/lib/generators/ab_admin/glob/templates/migration.erb +10 -7
  121. data/lib/generators/ab_admin/install/templates/config/ab_admin.rb.erb +1 -1
  122. data/lib/generators/ab_admin/install/templates/models/user.rb +1 -13
  123. data/lib/generators/ab_admin/install/templates/spec/spec_helper.rb +0 -1
  124. data/lib/generators/ab_admin/install/templates/spec/support/database_cleaner.rb +8 -11
  125. data/lib/generators/ab_admin/install/templates/uploaders/attachment_file_uploader.rb +1 -1
  126. data/lib/generators/ab_admin/install/templates/uploaders/avatar_uploader.rb +1 -1
  127. data/lib/generators/ab_admin/install/templates/uploaders/picture_uploader.rb +16 -3
  128. data/lib/generators/ab_admin/model/model_generator.rb +3 -4
  129. data/lib/generators/ab_admin/model/templates/resource.erb +5 -2
  130. data/lib/generators/ab_admin/resource/resource_generator.rb +0 -4
  131. data/lib/generators/ab_admin/resource/templates/controller.erb +2 -9
  132. data/lib/tasks/assets.rake +5 -5
  133. metadata +45 -85
  134. data/app/assets/images/admin/Jcrop.gif +0 -0
  135. data/app/assets/images/admin/flags/de.png +0 -0
  136. data/app/assets/images/admin/flags/en.png +0 -0
  137. data/app/assets/images/admin/flags/es.png +0 -0
  138. data/app/assets/images/admin/flags/fr.png +0 -0
  139. data/app/assets/images/admin/flags/it.png +0 -0
  140. data/app/assets/images/admin/flags/ja.png +0 -0
  141. data/app/assets/images/admin/flags/pl.png +0 -0
  142. data/app/assets/images/admin/flags/ru.png +0 -0
  143. data/app/assets/images/admin/flags/uk.png +0 -0
  144. data/app/assets/javascripts/ab_admin/components/croppable_image.js.coffee +0 -33
  145. data/app/assets/stylesheets/ab_admin/components/_columns_hider.scss +0 -5
  146. data/app/assets/stylesheets/ab_admin/components/_perms.scss +0 -39
  147. data/app/views/admin/shared/_columns_hider.html.slim +0 -9
  148. data/lib/ab_admin/hooks/globalize_locale_suffix_accessors.rb +0 -25
  149. data/lib/ab_admin/hooks/globalize_valid_locale.rb +0 -9
  150. data/lib/generators/ab_admin/ckeditor_assets/ckeditor_assets_generator.rb +0 -19
  151. data/lib/generators/template.rb +0 -96
@@ -3,44 +3,21 @@ module AbAdmin
3
3
  module Callbacks
4
4
  extend ActiveSupport::Concern
5
5
 
6
- #included do
7
- # define_admin_callbacks :build, :create, :update, :save, :destroy
8
- #end
9
-
10
6
  protected
11
7
 
12
- def build_resource
13
- object = get_resource_ivar || set_resource_ivar(end_of_association_chain.send(method_for_build, resource_params))
14
- # run_build_callbacks object
15
- object
16
- end
17
-
18
8
  def create_resource(object)
19
- run_create_callbacks object do
20
- save_resource(object)
21
- end
9
+ run_create_callbacks(object) {save_resource(object)}
22
10
  end
23
11
 
24
12
  def save_resource(object)
25
- run_save_callbacks object do
26
- object.save
27
- end
13
+ run_save_callbacks(object) {object.save}
28
14
  end
29
15
 
30
16
  def update_resource(object, attributes)
31
17
  object.assign_attributes(attributes)
32
-
33
- #run_update_callbacks object do
34
- save_resource(object)
35
- #end
18
+ save_resource(object)
36
19
  end
37
20
 
38
- #def destroy_resource(object)
39
- # run_destroy_callbacks object do
40
- # object.destroy
41
- # end
42
- #end
43
-
44
21
  # Simple callback system. Implements before and after callbacks for
45
22
  # use within the controllers.
46
23
  #
@@ -1,15 +1,4 @@
1
1
  class Array
2
- def add_or_delete(el)
3
- include?(el) ? delete(el) : push(el)
4
- end
5
-
6
- def word_count
7
- each_with_object({}) do |word, h|
8
- h[word] ||= 0
9
- h[word] += 1
10
- end
11
- end
12
-
13
2
  def deep_merge_hashes
14
3
  self.inject({}) do |res, h|
15
4
  raise Exception.new("Not a hash #{h}") unless h.is_a?(Hash)
@@ -22,30 +11,12 @@ class Array
22
11
  inject(:+) / size
23
12
  end
24
13
 
25
- #def zip_all
26
- # self[0].zip *self[1..-1]
27
- #end
28
- #
29
- #def pluck!(method, *args)
30
- # each_index { |x| self[x] = self[x].send method, *args }
31
- #end
32
- #
33
- #alias invoke! pluck!
34
-
35
- def without(*values)
36
- copy = self.dup
37
- copy.without!(*values)
38
- end
39
-
40
14
  def without!(*values)
15
+ ActiveSupport::Deprecation.warn('Array#without! is deprecated without replacement')
41
16
  values.flatten.each { |value| self.delete(value) }
42
17
  self
43
18
  end
44
19
 
45
- def map_val(attr='id')
46
- map{|el| el[attr] }
47
- end
48
-
49
20
  def contain?(other)
50
21
  (other - self).empty?
51
22
  end
@@ -53,24 +24,4 @@ class Array
53
24
  def intersect?(other)
54
25
  !(self & other).empty?
55
26
  end
56
-
57
- # def to_hash
58
- # ActiveSupport::Deprecation.warn('Array#to_hash is deprecated, use Array#to_h or Hash[] instead')
59
- # h = {}
60
- # each { |k, v| h[k] = v }
61
- # h
62
- # end
63
-
64
- def val_detect(attr, val)
65
- detect{|v| v[attr] == val }
66
- end
67
27
  end
68
-
69
- #module Enumerable
70
- # def pluck(method, *args)
71
- # map { |x| x.send method, *args }
72
- # end
73
- #
74
- # alias invoke pluck
75
- #end
76
-
@@ -1,5 +1,4 @@
1
1
  class Hash
2
-
3
2
  def reverse_deep_merge!(other_hash)
4
3
  other_hash.each_pair do |k, v|
5
4
  tv = self[k]
@@ -68,29 +67,13 @@ class Hash
68
67
  end
69
68
  end
70
69
 
71
- def val(*array)
72
- if array.empty?
73
- self
74
- else
75
- key = array.shift
76
- value = self[key]
77
- if array.empty?
78
- value
79
- elsif value.is_a? Hash
80
- value.val(*array)
81
- else
82
- nil
83
- end
84
- end
85
- end
86
-
87
- def store_multi(value, *keys)
70
+ def dig_store(value, *keys)
88
71
  key = keys.shift
89
72
  self[key] ||= {}
90
73
  if keys.empty?
91
74
  self[key] = value
92
75
  else
93
- self[key] = self[key].store_multi(value, *keys)
76
+ self[key] = self[key].dig_store(value, *keys)
94
77
  end
95
78
  self
96
79
  end
@@ -107,18 +90,6 @@ class Hash
107
90
  reject { |_, v| v.blank? }
108
91
  end
109
92
 
110
- def no_blank
111
- ActiveSupport::Deprecation.warn('`no_blank` is deprecated, use `reject_blank` instead')
112
- reject_blank
113
- end
114
-
115
- def try_keys(*try_keys)
116
- try_keys.each do |k|
117
- return self[k] if self.has_key?(k)
118
- end
119
- default
120
- end
121
-
122
93
  def deep_stringify_keys
123
94
  inject({}) { |result, (key, value)|
124
95
  value = value.deep_stringify_keys if value.is_a?(Hash)
@@ -1,9 +1,3 @@
1
- class NilClass
2
- def val(*args)
3
- self
4
- end
5
- end
6
-
7
1
  class TrueClass
8
2
  def to_i
9
3
  1
@@ -1,91 +1,6 @@
1
1
  class String
2
- # http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html
3
- #LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|`|"|~|\?|:|\\|\/)/
4
- #LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|`|"|~|\?|:|\\|\s)/
5
-
6
- KEYBOARDS = {
7
- en: 'qwertyuiop[]asdfghjkl;\'zxcvbnm,./',
8
- ru: 'йцукенгшщзхъфывапролджэячсмитьбю/'
9
- }
10
-
11
- unless defined? LUCENE_ESCAPE_REGEX
12
- LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|\^|"|~|\*|\?|:|\\|\/)/
13
-
14
- def lucene_escape
15
- self.gsub(LUCENE_ESCAPE_REGEX, "\\\\\\1")
16
- end
17
- end
18
-
19
- def capitalize_first
20
- self.mb_chars[0].capitalize + self.mb_chars[1..-1]
21
- end
22
-
23
- def is_int?
24
- self =~ /^[-+]?[0-9]+$/
25
- end
26
-
27
- def is_number?
28
- self =~ /^[-+]?[0-9]+(\.[0-9]+)?$/
29
- end
30
-
31
- def to_utc
32
- begin
33
- Time.zone.parse(self).utc
34
- rescue
35
- Time.now.utc
36
- end
37
- end
38
-
39
2
  def no_html
40
- str = self.dup
41
- str.gsub!(/<br\/?>/, ' ')
42
- str.gsub!(/<\/?[^>]*>/, '')
43
- str.strip!
44
- str.gsub!('&nbsp;', ' ')
45
- str
46
- end
47
-
48
- def tr_lang(from=nil, to=nil)
49
- return '' if self.blank?
50
-
51
- unless from || to
52
- if KEYBOARDS[:en].index(self[0])
53
- from, to = :en, :ru
54
- elsif KEYBOARDS[:ru].index(self[0])
55
- from, to = :ru, :en
56
- else
57
- from, to = :en, :ru
58
- end
59
- end
60
-
61
- self.tr(KEYBOARDS[from], KEYBOARDS[to])
62
- end
63
-
64
- def count_words
65
- clean_text.scan(/(\p{Alnum}+([-'.]\p{Alnum}+)*)/u).size
66
- end
67
-
68
- def words_count
69
- frequencies = Hash.new(0)
70
- downcase.scan(/(\w+([-'.]\w+)*)/) { |word, ignore| frequencies[word] += 1 }
71
- frequencies
72
- end
73
-
74
- def self.randomize(length = 8)
75
- Array.new(length) { (rand(122-97) + 97).chr }.join
76
- end
77
-
78
- def clean_text
79
- coder = HTMLEntities.new
80
- coder.decode(self.no_html)
81
- end
82
-
83
- def mb_upcase
84
- mb_chars.upcase.to_s
85
- end
86
-
87
- def mb_downcase
88
- mb_chars.downcase.to_s
3
+ self.dup.gsub(/<br\/?>/, ' ').gsub(/<\/?[^>]*>/, '').strip.gsub('&nbsp;', ' ').gsub('&gt;', '>').gsub('&lt;', '<')
89
4
  end
90
5
  end
91
6
 
@@ -29,6 +29,13 @@ module AbAdmin
29
29
  super
30
30
  end
31
31
  end
32
+
33
+ protected
34
+
35
+ def sign_in_params
36
+ devise_parameter_sanitizer.permit(:sign_in, keys: [:otp_attempt]) if devise_mapping.try(:two_factor_authenticatable?)
37
+ devise_parameter_sanitizer.sanitize(:sign_in)
38
+ end
32
39
  end
33
40
 
34
41
  class PasswordsController < ::Devise::PasswordsController
@@ -2,7 +2,7 @@ module AbAdmin
2
2
  class Engine < ::Rails::Engine
3
3
  engine_name 'ab_admin'
4
4
 
5
- initializer 'ab_admin.assets_precompile', :group => :all do |app|
5
+ initializer 'ab_admin.assets_precompile', group: :all do |app|
6
6
  app.config.assets.precompile += AbAdmin.assets
7
7
  end
8
8
 
@@ -19,6 +19,7 @@ module AbAdmin
19
19
  ActiveRecord::Base.send :extend, AbAdmin::Concerns::Silencer
20
20
  ActiveRecord::Base.send :include, AbAdmin::Concerns::Validations
21
21
  ActiveRecord::Base.send :include, AbAdmin::Concerns::Fileuploads
22
+ ActiveRecord::Base.send :extend, AbAdmin::Concerns::TranslationsMacro
22
23
  ActiveRecord::Base.send :extend, EnumField::EnumeratedAttribute
23
24
  end
24
25
 
@@ -0,0 +1,13 @@
1
+ begin
2
+ require 'ckeditor'
3
+
4
+ Ckeditor::Utils.module_eval do
5
+ class << self
6
+ def js_replace(dom_id, options = nil)
7
+ options.present? ? "lazyInitCkeditor('#{dom_id}', #{ActiveSupport::JSON.encode(options)});" : "lazyInitCkEditor('#{dom_id}');"
8
+ end
9
+ end
10
+ end
11
+ rescue LoadError => e
12
+ raise unless e.message.include?('ckeditor')
13
+ end
@@ -1,3 +1,5 @@
1
+ require 'will_paginate/active_record'
2
+
1
3
  # add `:large` option with make pagination on large tables easier, because `SELECT *` is slow with large `OFFSET`:
2
4
  # first it fetch ids of the records using `SELECT id`
3
5
  # and in the second query it fetch records
@@ -10,7 +12,7 @@ module WillPaginate
10
12
  if value.nil?
11
13
  paginate_limit || limit_value
12
14
  else
13
- limit(value)
15
+ limit(value.to_i)
14
16
  end
15
17
  end
16
18
 
@@ -18,7 +20,7 @@ module WillPaginate
18
20
  if value.nil?
19
21
  paginate_offset || offset_value
20
22
  else
21
- super(value)
23
+ super(value.to_i)
22
24
  end
23
25
  end
24
26
  end
@@ -26,8 +28,8 @@ module WillPaginate
26
28
  module Pagination
27
29
  def paginate(options)
28
30
  options = options.dup
29
- page_number = options.fetch(:page) { raise ArgumentError, ':page parameter required' }
30
- per_page = options.delete(:per_page) || self.per_page
31
+ page_number = [1, options[:page].to_i].max
32
+ per_page = (options.delete(:per_page) || self.per_page).to_i
31
33
  total = options.delete(:total_entries)
32
34
  large = options.delete(:large)
33
35
 
@@ -40,8 +42,8 @@ module WillPaginate
40
42
  rel.total_entries = total.to_i unless total.blank?
41
43
 
42
44
  if large
43
- ids = rel.except(:includes).pluck(Arel.sql("#{quoted_table_name}.id"))
44
- new_rel = rel.except(:limit, :offset, :where).where(id: ids)
45
+ ids = rel.except(:includes).pluck(Arel.sql("#{quoted_table_name}.#{primary_key}"))
46
+ new_rel = rel.except(:limit, :offset, :where).where(primary_key => ids)
45
47
  new_rel.paginate_limit = rel.limit_value.to_i
46
48
  new_rel.paginate_offset = rel.offset_value.to_i
47
49
  new_rel.total_entries = rel.total_entries
@@ -1,6 +1,6 @@
1
- # add `:no_uri` options to skip query params in pagination urls
2
1
  require 'will_paginate/view_helpers/action_view'
3
2
 
3
+ # add `:no_uri` options to skip query params in pagination urls
4
4
  WillPaginate::ViewHelpers.pagination_options[:no_uri] = false
5
5
  WillPaginate::ActionView::LinkRenderer.class_exec do
6
6
  def url(page)
@@ -19,7 +19,9 @@ module AbAdmin
19
19
 
20
20
  if response.code == 200
21
21
  json = MultiJson.decode(response)
22
- json['data']['translations'][0]['translatedText']
22
+ res = json['data']['translations'][0]['translatedText'].to_s.gsub(/%\s{/, ' %{')
23
+ res = "#{res[0].upcase}#{res[1..-1]}" if text.first[/[[:upper:]]/]
24
+ res
23
25
  else
24
26
  raise StandardError, response.inspect
25
27
  end
@@ -7,7 +7,7 @@ module AbAdmin
7
7
 
8
8
  def initialize(options: {})
9
9
  @options = options
10
- @locales = Globalize.available_locales
10
+ @locales = AbAdmin.translated_locales
11
11
  @models = AbAdmin.translate_models.map{|m| m.constantize }
12
12
  @models_i18n_hash = {}
13
13
  end
@@ -2,7 +2,6 @@ module AbAdmin
2
2
  module Menu
3
3
  class BaseGroup
4
4
  include ::Rails.application.routes.url_helpers
5
- include ::AbAdmin::Utils::EvalHelpers
6
5
 
7
6
  def link(title, path, options={})
8
7
  @menu_tree << Item.new(title, path, options)
@@ -10,9 +10,7 @@ module AbAdmin
10
10
  end
11
11
 
12
12
  def render(template)
13
- return if @options[:if] && !call_method_or_proc_on(template, @options[:if])
14
- return if @options[:unless] && call_method_or_proc_on(template, @options[:unless])
15
-
13
+ return unless template.option_conditions_met?(@options)
16
14
  wrapper_class = "dropdown-wrap-#{@raw_title}" if @raw_title.is_a?(Symbol)
17
15
  <<-HTML.html_safe
18
16
  <li class="dropdown #{wrapper_class}">
@@ -26,7 +24,7 @@ module AbAdmin
26
24
 
27
25
  def title(template)
28
26
  return @title unless @options[:badge]
29
- badge = call_method_or_proc_on(template, @options[:badge])
27
+ badge = @options[:badge].is_a?(Symbol) ? template.public_send(@options[:badge]) : template.instance_exec(&@options[:badge])
30
28
  return @title if !badge || badge == 0
31
29
  "#{@title}&nbsp;<span class='badge badge-#{@options[:badge_type] || 'important'}'>#{badge}</span>".html_safe
32
30
  end
@@ -1,8 +1,6 @@
1
1
  module AbAdmin
2
2
  module Menu
3
3
  class Item
4
- include ::AbAdmin::Utils::EvalHelpers
5
-
6
4
  def initialize(title, url, options)
7
5
  @title = title.is_a?(Symbol) ? I18n.t(title, scope: [:admin, :navigation]) : title
8
6
  @url = url
@@ -10,23 +8,21 @@ module AbAdmin
10
8
  end
11
9
 
12
10
  def render(template)
13
- return if @options[:if] && !call_method_or_proc_on(template, @options[:if])
14
- return if @options[:unless] && call_method_or_proc_on(template, @options[:unless])
11
+ return unless template.option_conditions_met?(@options)
15
12
 
16
- item_url = @url.is_a?(String) ? @url : call_method_or_proc_on(template, @url)
13
+ item_url = @url.is_a?(String) ? @url : template.instance_exec(&@url)
17
14
  active = template.request.path.split('/')[2] == item_url.split('/')[2]
18
15
 
19
16
  <<-HTML.html_safe
20
- <li class="#{'active' if active}">#{template.link_to title(template), item_url, @options.except(:if, :unless)}</li>
17
+ <li class="#{'active' if active}">#{template.link_to title(template), item_url, @options.except(:if, :unless, :badge)}</li>
21
18
  HTML
22
19
  end
23
20
 
24
21
  private
25
22
 
26
23
  def title(template)
27
- ActiveSupport::Deprecation.warn('Menu item :badge_counter option is deprecated, use :badge instead') if @options[:badge_counter]
28
24
  return @title unless @options[:badge]
29
- badge = call_method_or_proc_on(template, @options[:badge])
25
+ badge = @options[:badge].is_a?(Symbol) ? template.public_send(@options[:badge]) : template.instance_exec(&@options[:badge])
30
26
  return @title if !badge || badge == 0
31
27
  "#{@title}&nbsp;<span class='badge badge-#{@options[:badge_type] || 'important'}'>#{badge}</span>".html_safe
32
28
  end
@@ -30,7 +30,7 @@ module AbAdmin
30
30
 
31
31
  def ext_list
32
32
  return unless uploaders[:data]
33
- uploaders[:data].new.extension_whitelist
33
+ uploaders[:data].new.extension_allowlist
34
34
  end
35
35
 
36
36
  def clean!
@@ -76,14 +76,12 @@ module AbAdmin
76
76
  AbAdmin.image_types.include?(self.data_content_type)
77
77
  end
78
78
 
79
- def base_filename
80
- base = File.basename(data_file_name, '.*')
81
- base == data_secure_token ? File.basename(original_name, '.*') : base
79
+ def human_filename
80
+ data.human_part
82
81
  end
83
82
 
84
- def base_filename=(value)
85
- return false if value.blank? || File.basename(data_file_name, '.*') == value
86
- self.original_name = value + File.extname(data_file_name)
83
+ def human_filename=(value)
84
+ return if (human_filename.blank? && value.blank?) || human_filename == value
87
85
  rename!(value)
88
86
  end
89
87
 
@@ -116,14 +114,13 @@ module AbAdmin
116
114
 
117
115
  def rename!(name=nil)
118
116
  normalized_name = name ? data.normalize_filename(name) : rand(9999)
119
- return false if normalized_name.blank?
120
- data.rename_via_move "#{normalized_name}#{File.extname(data_file_name)}"
117
+ return if normalized_name.blank?
118
+ data.rename_via_move normalized_name
121
119
  end
122
120
 
123
121
  def refresh_assetable
124
122
  return unless assetable.try(:persisted?)
125
123
  assetable.touch
126
- assetable.tire.update_index if assetable.respond_to?(:tire)
127
124
  true
128
125
  end
129
126
 
@@ -24,12 +24,12 @@ module AbAdmin
24
24
  end
25
25
 
26
26
  def normalize_html
27
- ::Globalize.available_locales.each do |loc|
27
+ AbAdmin.translated_locales.each do |loc|
28
28
  %w(title h1 keywords description).each do |attr|
29
29
  send("#{attr}_#{loc}=", send("#{attr}_#{loc}").to_s.no_html)
30
30
  end
31
31
  end
32
- ::Globalize.available_locales.each do |loc|
32
+ AbAdmin.translated_locales.each do |loc|
33
33
  send("seo_block_#{loc}=", sanitize(send("seo_block_#{loc}").to_s))
34
34
  end
35
35
  end
@@ -58,12 +58,38 @@ module AbAdmin
58
58
  csv_data.each do |d|
59
59
  key_parts = [l.to_s] + d[0].split('.')
60
60
  raise "Invalid key #{d[0]}" unless data.dig(*key_parts)
61
- data.store_multi(d[i], *key_parts)
61
+ data.dig_store(d[i], *key_parts)
62
62
  end
63
63
  save path, data
64
64
  end
65
65
  end
66
66
 
67
+ INTERPOLATION_REGEXP = /%{[^}]+}/
68
+ def csv_errors(csv)
69
+ return ['CSV blank'] if csv.blank?
70
+ csv_data = CSV.parse(csv)
71
+ errors = []
72
+ csv_data.shift.each_with_index do |l, i|
73
+ next if i.zero?
74
+ unless I18n.available_locales.include?(l.to_sym)
75
+ errors << "Unknown locale #{l}"
76
+ next
77
+ end
78
+ csv_data.each do |d|
79
+ key = d[0]
80
+ next if d[i].blank?
81
+ if translations.dig(I18n.default_locale, key)
82
+ unless translations.dig(I18n.default_locale, key).scan(INTERPOLATION_REGEXP).sort == d[i].scan(INTERPOLATION_REGEXP).sort
83
+ errors << "Wrong interpolations #{I18n.default_locale}:'#{translations.dig(I18n.default_locale, key)}' #{l}:#{d[i]}"
84
+ end
85
+ else
86
+ errors << "Extra interpolations #{l}:#{d[i]}" if d[i].scan(INTERPOLATION_REGEXP).present?
87
+ end
88
+ end
89
+ end
90
+ errors
91
+ end
92
+
67
93
  def translations
68
94
  @translations ||= I18n.backend.send(:translations).slice(*I18n.available_locales).transform_values{|v| v.flatten_hash.transform_keys{|k| k.join('.') } }
69
95
  end
@@ -93,7 +119,7 @@ module AbAdmin
93
119
  message = nil
94
120
  locale_replace_regexp = Regexp.new("(^#{I18n.default_locale}|(?<=\.)#{I18n.default_locale}(?=\.yml))")
95
121
 
96
- locale_files = @files.map { |path| self.class.prepare_data(path) }
122
+ locale_files = @files.find_all{|f| f =~ /\/\w+(\.readonly)?\.yml/ }.map { |path| self.class.prepare_data(path) }
97
123
  main_locale_files = locale_files.find_all { |file| file.locale == I18n.default_locale }
98
124
 
99
125
  main_locale_files.each do |main_file|
@@ -101,7 +127,7 @@ module AbAdmin
101
127
  next if locale == I18n.default_locale
102
128
  clean_locale_hash = main_file.data.deep_clear_values
103
129
  path = File.join(main_file.dir, main_file.filename.sub(locale_replace_regexp, locale.to_s))
104
- if File.exists?(path)
130
+ if File.exist?(path)
105
131
  file = self.class.prepare_data(path)
106
132
  self.class.save(path, {locale.to_s => clean_locale_hash.deep_add(file.data)})
107
133
  else
@@ -38,7 +38,7 @@ module AbAdmin
38
38
  end
39
39
 
40
40
  def read_data
41
- paths = base_paths.dup.push(editable_path).compact.find_all { |path| File.exists?(path) }
41
+ paths = base_paths.dup.push(editable_path).compact.find_all { |path| File.exist?(path) }
42
42
  hash = paths.map{|path| YAML.safe_load(File.read(path)) }.inject(&:deep_merge).deep_symbolize_keys
43
43
  SettingsStruct.new(hash)
44
44
  end
@@ -53,7 +53,7 @@ module AbAdmin
53
53
  end
54
54
 
55
55
  def editable_path
56
- editable_paths.detect { |path| File.exists?(path) }
56
+ editable_paths.detect { |path| File.exist?(path) }
57
57
  end
58
58
  end
59
59
 
@@ -15,12 +15,12 @@ module AbAdmin
15
15
  validates_numericality_of :structure_type_id, only_integer: true
16
16
 
17
17
  has_one :static_page, dependent: :destroy
18
- has_many :visible_children, -> { where(is_visible: true) }, class_name: name, foreign_key: 'parent_id'
18
+ has_many :visible_children, -> { where(is_visible: true) }, class_name: name, foreign_key: :parent_id
19
19
 
20
20
  scope :visible, lambda { where(is_visible: true) }
21
- scope :with_type, lambda { |structure_type| where(structure_type_id: structure_type.id) }
21
+ scope :with_type, lambda { |type| where(structure_type_id: (type.is_a?(Symbol) ? StructureType.public_send(type) : type.id)) }
22
22
  scope :with_depth, lambda { |level| where(depth: level.to_i) }
23
- scope :with_position, lambda { |position_type| where(position_type_id: position_type.id).order('lft DESC') }
23
+ scope :with_position, lambda { |type| where(position_type_id: (type.is_a?(Symbol) ? StructureType.public_send(type) : type.id)).order(lft: :desc) }
24
24
  end
25
25
 
26
26
  def redirect?
@@ -44,9 +44,9 @@ module AbAdmin
44
44
  lookups << ['actions', key]
45
45
  end
46
46
  lookups.map!{|l| l.join('.').to_sym }
47
- lookups << key
47
+ lookups << parts.last.humanize
48
48
 
49
- I18n.t(lookups.shift, (parameters.merge(params) || {}).merge(scope: :admin, default: lookups))
49
+ I18n.t(lookups.shift, **(parameters.merge(params) || {}).merge(scope: :admin, default: lookups))
50
50
  end
51
51
 
52
52
  def trackable_changed_attrs
@@ -63,7 +63,19 @@ module AbAdmin
63
63
 
64
64
  def make_trackable
65
65
  self.name ||= trackable.han.first(250)
66
- self.trackable_changes = trackable.saved_changes.except(:updated_at)
66
+ self.trackable_changes = format_trackable_changes(trackable.saved_changes.except(:updated_at))
67
+ end
68
+
69
+ def format_trackable_changes(value)
70
+ value.to_h.deep_transform_values do |v|
71
+ if v.is_a?(BigDecimal)
72
+ v.to_f
73
+ elsif v.is_a?(ActiveSupport::TimeWithZone)
74
+ v.to_s
75
+ else
76
+ v
77
+ end
78
+ end
67
79
  end
68
80
  end
69
81
  end