avo 0.3.2 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of avo might be problematic. Click here for more details.

Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -2
  3. data/Gemfile.lock +8 -1
  4. data/app/controllers/avo/application_controller.rb +2 -2
  5. data/app/controllers/avo/relations_controller.rb +2 -2
  6. data/app/controllers/avo/resource_overview_controller.rb +1 -0
  7. data/app/controllers/avo/resources_controller.rb +5 -3
  8. data/app/views/layouts/avo/_javascript.html.erb +2 -0
  9. data/app/views/layouts/avo/_translations.html.erb +5 -0
  10. data/app/views/layouts/avo/application.html.erb +7 -2
  11. data/avo.gemspec +1 -0
  12. data/lib/avo.rb +2 -0
  13. data/lib/avo/app/action.rb +8 -5
  14. data/lib/avo/app/app.rb +21 -3
  15. data/lib/avo/app/fields/belongs_to.rb +2 -2
  16. data/lib/avo/app/fields/code_field.rb +2 -0
  17. data/lib/avo/app/fields/country_field.rb +1 -1
  18. data/lib/avo/app/fields/field.rb +3 -1
  19. data/lib/avo/app/fields/field_extensions/visible_in_different_views.rb +4 -0
  20. data/lib/avo/app/fields/has_one.rb +2 -2
  21. data/lib/avo/app/fields/markdown_field.rb +27 -0
  22. data/lib/avo/app/fields/password_field.rb +3 -1
  23. data/lib/avo/app/fields/select_field.rb +1 -1
  24. data/lib/avo/app/licensing/hq.rb +4 -3
  25. data/lib/avo/app/resource.rb +18 -7
  26. data/lib/avo/app/{authorization_service.rb → services/authorization_service.rb} +0 -0
  27. data/lib/avo/configuration.rb +14 -2
  28. data/lib/avo/engine.rb +5 -5
  29. data/lib/avo/version.rb +1 -1
  30. data/lib/generators/avo/install_generator.rb +2 -1
  31. data/lib/generators/avo/templates/{initializer.rb → initializer/avo.rb} +0 -0
  32. data/lib/generators/avo/templates/locales/avo.en.yml +60 -0
  33. data/public/avo-packs/css/application-2f609d81.css +3 -0
  34. data/public/avo-packs/css/application-2f609d81.css.br +0 -0
  35. data/public/avo-packs/css/application-2f609d81.css.gz +0 -0
  36. data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js +3 -0
  37. data/public/avo-packs/js/{application-725ee54e3adbcd950843.js.LICENSE.txt → application-84e2d573c3c15df1fb7b.js.LICENSE.txt} +0 -0
  38. data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.br +0 -0
  39. data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.gz +0 -0
  40. data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.map +1 -0
  41. data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.map.br +0 -0
  42. data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.map.gz +0 -0
  43. data/public/avo-packs/manifest.json +11 -6
  44. data/public/avo-packs/manifest.json.br +0 -0
  45. data/public/avo-packs/manifest.json.gz +0 -0
  46. data/public/avo-packs/media/font/fontello-068ca2b3.ttf +0 -0
  47. data/public/avo-packs/media/font/fontello-068ca2b3.ttf.br +0 -0
  48. data/public/avo-packs/media/font/fontello-068ca2b3.ttf.gz +0 -0
  49. data/public/avo-packs/media/font/fontello-8d4a4e6f.woff2 +0 -0
  50. data/public/avo-packs/media/font/fontello-9354499c.svg +72 -0
  51. data/public/avo-packs/media/font/fontello-9354499c.svg.br +0 -0
  52. data/public/avo-packs/media/font/fontello-9354499c.svg.gz +0 -0
  53. data/public/avo-packs/media/font/fontello-a782baa8.woff +0 -0
  54. data/public/avo-packs/media/font/fontello-e73a0647.eot +0 -0
  55. data/public/avo-packs/media/font/fontello-e73a0647.eot.br +0 -0
  56. data/public/avo-packs/media/font/fontello-e73a0647.eot.gz +0 -0
  57. metadata +42 -14
  58. data/public/avo-packs/css/application-73e568bc.css +0 -3
  59. data/public/avo-packs/css/application-73e568bc.css.br +0 -0
  60. data/public/avo-packs/css/application-73e568bc.css.gz +0 -0
  61. data/public/avo-packs/js/application-725ee54e3adbcd950843.js +0 -3
  62. data/public/avo-packs/js/application-725ee54e3adbcd950843.js.br +0 -0
  63. data/public/avo-packs/js/application-725ee54e3adbcd950843.js.gz +0 -0
  64. data/public/avo-packs/js/application-725ee54e3adbcd950843.js.map +0 -1
  65. data/public/avo-packs/js/application-725ee54e3adbcd950843.js.map.br +0 -0
  66. data/public/avo-packs/js/application-725ee54e3adbcd950843.js.map.gz +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7fc8f29ce910c3eeb8bb2d80e61bc7b65385fd0b4bbb71ef9cf85556cf943bc3
4
- data.tar.gz: 277415ac5daec5c8985d3ee62e2ec3dd779ea23df8b5fbc0993fb64da774a54a
3
+ metadata.gz: 12b4c2f7a1b63d7296ac6f9b8edb5f133884ca5b10d1ed5c5a85e230364dad07
4
+ data.tar.gz: 5dd72ab388c40de38a1a36e3bf077360afabf0e75fe1922feec31f1cc9cd7913
5
5
  SHA512:
6
- metadata.gz: e44bf33db4a90366e85780d500d0d476b22b74a8cdec88bb39c1da5e86e5dad6c866bef3f5ab8386f6a51b382aa1ec19ec2f8d20e3aa940ced316d8ca3558701
7
- data.tar.gz: 2365d6464818c443ccb4808c041c084d1cfa5a795e63419e90524be642c64c817249e59b69b27d569ba97247c50089a58511c8f45d2106716f1d028bb506c3d6
6
+ metadata.gz: d2369b3f99c6244a3e0a4966cac220283f2f2bef7c99edbc31e56407f4a3100460691b663486a7bf96626eee5086861e3295f6e04f066cedff79c25f9b4927c5
7
+ data.tar.gz: d98ce0432dfa0157ea480f21bb028c65bc33e9e2a59e88731efbde478806dcae96a04524ce04993741778329bddaa7083a8be69b71bea4b1282b2219550e2b01
data/Gemfile CHANGED
@@ -59,8 +59,7 @@ gem 'spring'
59
59
  gem 'spring-watcher-listen', '~> 2.0.0'
60
60
 
61
61
  gem 'factory_bot_rails'
62
- gem 'faker'
63
-
62
+ gem 'faker', require: false
64
63
  # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
65
64
  gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
66
65
 
@@ -94,3 +93,7 @@ gem 'zeitwerk', '~> 2.3'
94
93
  gem 'kaminari'
95
94
 
96
95
  gem 'httparty'
96
+
97
+ gem 'iso'
98
+
99
+ gem 'i18n-js'
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (0.3.2)
4
+ avo (0.4.1)
5
5
  countries
6
6
  httparty
7
+ i18n-js
7
8
  inline_svg
8
9
  kaminari
9
10
  pundit
@@ -132,10 +133,14 @@ GEM
132
133
  multi_xml (>= 0.5.2)
133
134
  i18n (1.8.5)
134
135
  concurrent-ruby (~> 1.0)
136
+ i18n-js (3.8.0)
137
+ i18n (>= 0.6.6)
135
138
  i18n_data (0.10.0)
136
139
  inline_svg (1.7.1)
137
140
  activesupport (>= 3.0)
138
141
  nokogiri (>= 1.6)
142
+ iso (0.3.0)
143
+ i18n
139
144
  jbuilder (2.10.1)
140
145
  activesupport (>= 5.0.0)
141
146
  kaminari (1.2.1)
@@ -341,7 +346,9 @@ DEPENDENCIES
341
346
  fuubar
342
347
  gem-release
343
348
  httparty
349
+ i18n-js
344
350
  inline_svg
351
+ iso
345
352
  jbuilder (~> 2.7)
346
353
  kaminari
347
354
  listen (>= 3.0.5, < 3.2)
@@ -5,7 +5,7 @@ module Avo
5
5
  before_action :init_app
6
6
 
7
7
  def init_app
8
- Avo::App.boot unless Rails.env.production?
8
+ Avo::App.boot if Avo::IN_DEVELOPMENT
9
9
  Avo::App.init request
10
10
 
11
11
  @license = Avo::App.license
@@ -58,7 +58,7 @@ module Avo
58
58
  end
59
59
 
60
60
  def render_unauthorized
61
- render json: { message: 'Unauthorized' }, status: 403
61
+ render json: { message: I18n.t('avo.unauthorized') }, status: 403
62
62
  end
63
63
  end
64
64
  end
@@ -9,7 +9,7 @@ module Avo
9
9
 
10
10
  render json: {
11
11
  success: true,
12
- message: "#{attachment_class} attached.",
12
+ message: I18n.t('avo.attachment_class_attached', attachment_class: attachment_class),
13
13
  }
14
14
  end
15
15
 
@@ -18,7 +18,7 @@ module Avo
18
18
 
19
19
  render json: {
20
20
  success: true,
21
- message: "#{attachment_class} attached.",
21
+ message: I18n.t('avo.attachment_class_detached', attachment_class: attachment_class),
22
22
  }
23
23
  end
24
24
 
@@ -5,6 +5,7 @@ module Avo
5
5
  def index
6
6
  resources = App.get_resources
7
7
  .select { |resource| AuthorizationService::authorize session_user, resource.model, Avo.configuration.authorization_methods.stringify_keys['index'] }
8
+ .sort_by(&:name)
8
9
  .map do |resource|
9
10
  {
10
11
  name: resource.name,
@@ -95,7 +95,7 @@ module Avo
95
95
  render json: {
96
96
  success: true,
97
97
  resource: Avo::Resources::Resource.hydrate_resource(model: resource, resource: avo_resource, view: :show, user: current_user),
98
- message: 'Resource updated',
98
+ message: I18n.t('avo.resource_updated'),
99
99
  }
100
100
  end
101
101
 
@@ -118,7 +118,7 @@ module Avo
118
118
  render json: {
119
119
  success: true,
120
120
  resource: Avo::Resources::Resource.hydrate_resource(model: resource, resource: avo_resource, view: :create, user: current_user),
121
- message: 'Resource created',
121
+ message: I18n.t('avo.resource_created'),
122
122
  }
123
123
  end
124
124
 
@@ -132,7 +132,7 @@ module Avo
132
132
  resource.destroy!
133
133
 
134
134
  render json: {
135
- message: 'Resource destroyed',
135
+ message: I18n.t('avo.resource_destroyed'),
136
136
  }
137
137
  end
138
138
 
@@ -255,8 +255,10 @@ module Avo
255
255
  per_page_steps: Avo.configuration.per_page_steps,
256
256
  available_view_types: avo_resource.available_view_types,
257
257
  default_view_type: avo_resource.default_view_type || Avo.configuration.default_view_type,
258
+ translation_key: avo_resource.translation_key,
258
259
  authorization: {
259
260
  create: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['create']),
261
+ edit: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['edit']),
260
262
  update: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['update']),
261
263
  show: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['show']),
262
264
  destroy: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['destroy']),
@@ -1,6 +1,8 @@
1
1
  <script>
2
2
  var rootPath = '<%= Avo.configuration.root_path %>';
3
3
  var timezone = '<%= Avo.configuration.timezone %>';
4
+ var locale = '<%= Avo.configuration.locale %>';
4
5
  var defaultViewType = '<%= Avo.configuration.default_view_type %>';
5
6
  var license = <%= Avo::App.license.properties.to_json.html_safe %>;
7
+ var avoResources = <%= Avo::App.get_available_resources(current_user).as_json.html_safe %>;
6
8
  </script>
@@ -0,0 +1,5 @@
1
+ <script>
2
+ I18n.defaultLocale = 'en';
3
+ I18n.locale = "<%= Avo.configuration.language_code %>";
4
+ </script>
5
+ <%= javascript_include_tag 'translations', skip_pipeline: true %>
@@ -8,8 +8,10 @@
8
8
 
9
9
  <%= javascript_pack_tag 'application' %>
10
10
  <%= stylesheet_pack_tag 'application', media: 'all' %>
11
+ <%= render partial: 'layouts/avo/translations' %>
11
12
  <link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;700;900&display=swap" rel="stylesheet">
12
13
  </head>
14
+
13
15
  <body class="bg-gray-200">
14
16
 
15
17
  <div id="app" class="flex min-h-screen flex-row h-full">
@@ -19,7 +21,7 @@
19
21
  inline-template
20
22
  >
21
23
  <div>
22
- <application-sidebar :resources='<%= Avo::App.get_resources_navigation(current_user).as_json.html_safe %>' v-if="layout !== 'blank'">
24
+ <application-sidebar v-if="layout !== 'blank'">
23
25
  <template #logo>
24
26
  <%= render_logo %>
25
27
  </template>
@@ -29,7 +31,7 @@
29
31
  </application-sidebar>
30
32
 
31
33
  <div class="flex-1 h-full overflow-auto">
32
- <div class="relative bg-white p-2 shadow-md h-16 w-full flex items-center z-40" v-if="layout !== 'blank'">
34
+ <div class="relative bg-white p-2 shadow-md h-16 w-full flex items-center z-50" v-if="layout !== 'blank'">
33
35
  <div class="ml-6">
34
36
  <%= render_header %>
35
37
  </div>
@@ -43,6 +45,7 @@
43
45
  <div v-if="layout === 'blank'" class="h-full w-full flex justify-center items-center">
44
46
  <%= yield %>
45
47
  </div>
48
+
46
49
  <div class="content p-8" v-else>
47
50
  <%= yield %>
48
51
  <%= render_footer %>
@@ -51,6 +54,8 @@
51
54
  </div>
52
55
  </app-layout>
53
56
  </div>
57
+
54
58
  <%= render_scripts %>
59
+
55
60
  </body>
56
61
  </html>
@@ -40,4 +40,5 @@ Gem::Specification.new do |spec|
40
40
  spec.add_dependency 'countries'
41
41
  spec.add_dependency 'pundit'
42
42
  spec.add_dependency 'httparty'
43
+ spec.add_dependency 'i18n-js'
43
44
  end
data/lib/avo.rb CHANGED
@@ -15,6 +15,8 @@ require_relative 'avo/app/licensing/license_manager'
15
15
 
16
16
  module Avo
17
17
  ROOT_PATH = Pathname.new(File.join(__dir__, '..'))
18
+ IN_DEVELOPMENT = ENV['AVO_IN_DEVELOPMENT'] == '1'
19
+ PACKED = !IN_DEVELOPMENT
18
20
 
19
21
  class << self
20
22
  def webpacker
@@ -15,6 +15,7 @@ module Avo
15
15
  # filename: String
16
16
  # }
17
17
  attr_accessor :response
18
+ attr_accessor :no_confirmation
18
19
 
19
20
  @@default = nil
20
21
 
@@ -37,15 +38,16 @@ module Avo
37
38
 
38
39
  def initialize
39
40
  @name ||= name
40
- @message ||= 'Are you sure you want to run this action?'
41
+ @message ||= I18n.t('avo.are_you_sure_you_want_to_run_this_option')
41
42
  @default ||= ''
42
43
  @fields ||= []
43
- @confirm_text = 'Run'
44
- @cancel_text = 'Cancel'
44
+ @confirm_text = I18n.t('avo.run')
45
+ @cancel_text = I18n.t('avo.cancel')
45
46
  @response ||= {}
46
47
  @response[:message_type] ||= :success
47
- @response[:message] ||= 'Action ran successfully!'
48
+ @response[:message] ||= I18n.t('avo.action_ran_successfully')
48
49
  @theme ||= 'success'
50
+ @no_confirmation ||= false
49
51
  end
50
52
 
51
53
  def render_response(model, resource)
@@ -61,6 +63,7 @@ module Avo
61
63
  cancel_text: cancel_text,
62
64
  default: default,
63
65
  action_class: self.class.to_s,
66
+ no_confirmation: no_confirmation,
64
67
  }
65
68
  end
66
69
 
@@ -87,7 +90,7 @@ module Avo
87
90
  end
88
91
 
89
92
  def name
90
- self.class.name.demodulize.underscore.humanize
93
+ self.class.name.demodulize.underscore.humanize(keep_id_suffix: true)
91
94
  end
92
95
 
93
96
  def succeed(text)
@@ -4,7 +4,7 @@ require_relative 'filters/select_filter'
4
4
  require_relative 'filters/boolean_filter'
5
5
  require_relative 'resource'
6
6
  require_relative 'tool'
7
- require_relative 'authorization_service'
7
+ require_relative 'services/authorization_service'
8
8
 
9
9
  module Avo
10
10
  class App
@@ -12,6 +12,7 @@ module Avo
12
12
  root_path: '',
13
13
  resources: [],
14
14
  field_names: {},
15
+ cache_store: nil
15
16
  }
16
17
  @@license = nil
17
18
 
@@ -19,6 +20,13 @@ module Avo
19
20
  def boot
20
21
  @@app[:root_path] = Pathname.new(File.join(__dir__, '..', '..'))
21
22
  init_fields
23
+ I18n.locale = Avo.configuration.language_code
24
+
25
+ if Rails.cache.class == ActiveSupport::Cache::NullStore
26
+ @@app[:cache_store] ||= ActiveSupport::Cache::MemoryStore.new
27
+ else
28
+ @@app[:cache_store] = Rails.cache
29
+ end
22
30
  end
23
31
 
24
32
  def init(current_request = nil)
@@ -34,6 +42,10 @@ module Avo
34
42
  @@license
35
43
  end
36
44
 
45
+ def cache_store
46
+ @@app[:cache_store]
47
+ end
48
+
37
49
  # This method will take all fields available in the Avo::Fields namespace and create a method for them.
38
50
  #
39
51
  # If the field has their `def_method` set up it will follow that convention, if not it will snake_case the name:
@@ -127,10 +139,16 @@ module Avo
127
139
  name.to_s.camelize.singularize
128
140
  end
129
141
 
130
- def get_resources_navigation(user)
142
+ def get_available_resources(user)
131
143
  App.get_resources
132
144
  .select { |resource| AuthorizationService::authorize user, resource.model, Avo.configuration.authorization_methods.stringify_keys['index'] }
133
- .map { |resource| { label: resource.resource_name_plural.humanize, resource_name: resource.url.pluralize } }
145
+ .map do |resource|
146
+ {
147
+ label: resource.plural_name.humanize(keep_id_suffix: true),
148
+ resource_name: resource.url.pluralize,
149
+ translation_key: resource.translation_key
150
+ }
151
+ end
134
152
  .reject { |i| i.blank? }
135
153
  .to_json
136
154
  .to_s
@@ -7,7 +7,7 @@ module Avo
7
7
  def initialize(name, **args, &block)
8
8
  @defaults = {
9
9
  component: 'belongs-to-field',
10
- placeholder: "Choose #{name.downcase}",
10
+ placeholder: I18n.t('avo.choose_an_option')
11
11
  }
12
12
 
13
13
  @searchable = args[:searchable] == true ? true : false
@@ -49,7 +49,7 @@ module Avo
49
49
  end
50
50
  end
51
51
 
52
- fields[:resource_name_plural] = target_resource.resource_name_plural
52
+ fields[:plural_name] = target_resource.plural_name
53
53
 
54
54
  fields
55
55
  end
@@ -12,12 +12,14 @@ module Avo
12
12
 
13
13
  @language = args[:language].present? ? args[:language].to_s : 'javascript'
14
14
  @theme = args[:theme].present? ? args[:theme].to_s : 'material-darker'
15
+ @height = args[:height].present? ? args[:height].to_s : 'auto'
15
16
  end
16
17
 
17
18
  def hydrate_field(fields, model, resource, view)
18
19
  {
19
20
  language: @language,
20
21
  theme: @theme,
22
+ height: @height,
21
23
  }
22
24
  end
23
25
  end
@@ -5,7 +5,7 @@ module Avo
5
5
  @defaults = {
6
6
  sortable: true,
7
7
  component: 'country-field',
8
- placeholder: 'Choose a country',
8
+ placeholder: I18n.t('avo.choose_a_country'),
9
9
  }
10
10
 
11
11
  super(name, **args, &block)
@@ -9,6 +9,7 @@ module Avo
9
9
 
10
10
  attr_accessor :id
11
11
  attr_accessor :name
12
+ attr_accessor :translation_key
12
13
  attr_accessor :component
13
14
  attr_accessor :updatable
14
15
  attr_accessor :sortable
@@ -35,7 +36,8 @@ module Avo
35
36
  # The field properties as a hash {property: default_value}
36
37
  @field_properties = {
37
38
  id: id,
38
- name: id.to_s.humanize,
39
+ name: id.to_s.humanize(keep_id_suffix: true),
40
+ translation_key: nil,
39
41
  block: block,
40
42
  component: 'field',
41
43
  required: false,
@@ -15,12 +15,16 @@ module Avo
15
15
  end
16
16
 
17
17
  def show_on(*where)
18
+ return show_on_all if where.include? :all
19
+
18
20
  normalize_views(where).flatten.each do |view|
19
21
  show_on_view view
20
22
  end
21
23
  end
22
24
 
23
25
  def hide_on(*where)
26
+ return hide_on_all if where.include? :all
27
+
24
28
  normalize_views(where).flatten.each do |view|
25
29
  hide_on_view view
26
30
  end
@@ -13,7 +13,7 @@ module Avo
13
13
 
14
14
  hide_on :create
15
15
 
16
- @placeholder = 'Choose an option'
16
+ @placeholder = I18n.t 'avo.choose_an_option'
17
17
 
18
18
  @relation_method = name.to_s.parameterize.underscore
19
19
  end
@@ -43,7 +43,7 @@ module Avo
43
43
  end
44
44
  end
45
45
 
46
- fields[:resource_name_plural] = target_resource.resource_name_plural
46
+ fields[:plural_name] = target_resource.plural_name
47
47
 
48
48
  fields
49
49
  end
@@ -0,0 +1,27 @@
1
+ require_relative 'field'
2
+
3
+ module Avo
4
+ module Fields
5
+ class MarkdownField < Field
6
+ def initialize(name, **args, &block)
7
+ @defaults = {
8
+ component: 'markdown-field',
9
+ }
10
+
11
+ super(name, **args, &block)
12
+
13
+ hide_on :index
14
+
15
+ @always_show = args[:always_show].present? ? args[:always_show] : false
16
+ @height = args[:height].present? ? args[:height].to_s : 'auto'
17
+ end
18
+
19
+ def hydrate_field(fields, model, resource, view)
20
+ {
21
+ always_show: @always_show,
22
+ height: @height
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end