ab_admin 0.8.3 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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