admin_core 0.0.1

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 (173) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +2 -0
  3. data/.gitignore +53 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +27 -0
  6. data/CHANGELOG.md +15 -0
  7. data/Gemfile +3 -0
  8. data/README.md +48 -0
  9. data/Rakefile +31 -0
  10. data/admin_core.gemspec +32 -0
  11. data/client/.babelrc +19 -0
  12. data/client/.eslintignore +3 -0
  13. data/client/.eslintrc.yml +20 -0
  14. data/client/.flowconfig +7 -0
  15. data/client/.gitignore +64 -0
  16. data/client/README.md +3 -0
  17. data/client/admin-core.scss +8 -0
  18. data/client/flow-typed/npm/axios_v0.16.x.js +120 -0
  19. data/client/flow-typed/npm/classnames_v2.x.x.js +16 -0
  20. data/client/flow-typed/npm/lodash_v4.x.x.js +514 -0
  21. data/client/flow-typed/npm/react-router-dom_v4.x.x.js +166 -0
  22. data/client/flow-typed/npm/reactstrap_vx.x.x.js +536 -0
  23. data/client/package.json +60 -0
  24. data/client/src/.eslintrc.yml +23 -0
  25. data/client/src/AdminCore.jsx +44 -0
  26. data/client/src/components/Breadcrumb.jsx +18 -0
  27. data/client/src/components/Header.jsx +45 -0
  28. data/client/src/components/Pagination.jsx +72 -0
  29. data/client/src/components/ResourceFilters.jsx +87 -0
  30. data/client/src/components/ResourceForm.jsx +103 -0
  31. data/client/src/components/ResourcesCollection.jsx +41 -0
  32. data/client/src/components/Sidebar.jsx +90 -0
  33. data/client/src/decls.js +119 -0
  34. data/client/src/http-client.js +18 -0
  35. data/client/src/main.js +9 -0
  36. data/client/src/resource-field/BelongsTo.jsx +26 -0
  37. data/client/src/resource-field/Boolean.jsx +43 -0
  38. data/client/src/resource-field/Date.jsx +29 -0
  39. data/client/src/resource-field/DateTime.jsx +29 -0
  40. data/client/src/resource-field/Enum.jsx +34 -0
  41. data/client/src/resource-field/Number.jsx +28 -0
  42. data/client/src/resource-field/String.jsx +28 -0
  43. data/client/src/resource-field/Text.jsx +27 -0
  44. data/client/src/resource-field-renderer.js +45 -0
  45. data/client/src/resource-filter/Boolean.jsx +22 -0
  46. data/client/src/resource-filter/Number.jsx +45 -0
  47. data/client/src/resource-filter/String.jsx +46 -0
  48. data/client/src/resource-filter-renderer.js +17 -0
  49. data/client/src/resource-page/Base.js +36 -0
  50. data/client/src/resource-page/Edit.jsx +48 -0
  51. data/client/src/resource-page/Index.jsx +141 -0
  52. data/client/src/resource-page/New.jsx +48 -0
  53. data/client/src/resource-page/Show.jsx +116 -0
  54. data/client/webpack.config.js +26 -0
  55. data/client/yarn.lock +3816 -0
  56. data/lib/admin_core/base_controller.rb +114 -0
  57. data/lib/admin_core/base_resource_manager.rb +24 -0
  58. data/lib/admin_core/configuration.rb +20 -0
  59. data/lib/admin_core/engine.rb +6 -0
  60. data/lib/admin_core/errors.rb +17 -0
  61. data/lib/admin_core/resource_field/base.rb +69 -0
  62. data/lib/admin_core/resource_field/belongs_to.rb +38 -0
  63. data/lib/admin_core/resource_field/boolean.rb +18 -0
  64. data/lib/admin_core/resource_field/date.rb +18 -0
  65. data/lib/admin_core/resource_field/date_time.rb +18 -0
  66. data/lib/admin_core/resource_field/enum.rb +26 -0
  67. data/lib/admin_core/resource_field/number.rb +18 -0
  68. data/lib/admin_core/resource_field/string.rb +18 -0
  69. data/lib/admin_core/resource_field/text.rb +23 -0
  70. data/lib/admin_core/resource_field_builder.rb +48 -0
  71. data/lib/admin_core/resource_filter/base.rb +63 -0
  72. data/lib/admin_core/resource_filter/boolean.rb +17 -0
  73. data/lib/admin_core/resource_filter/number.rb +25 -0
  74. data/lib/admin_core/resource_filter/string.rb +27 -0
  75. data/lib/admin_core/resource_filter_builder.rb +37 -0
  76. data/lib/admin_core/resource_manager/buildable.rb +42 -0
  77. data/lib/admin_core/resource_manager/convert.rb +95 -0
  78. data/lib/admin_core/resource_manager/has_many_fields.rb +71 -0
  79. data/lib/admin_core/resource_manager/permission.rb +35 -0
  80. data/lib/admin_core/resource_manager/searchable.rb +57 -0
  81. data/lib/admin_core/resource_page/base.rb +17 -0
  82. data/lib/admin_core/resource_page/edit.rb +22 -0
  83. data/lib/admin_core/resource_page/index.rb +52 -0
  84. data/lib/admin_core/resource_page/new.rb +26 -0
  85. data/lib/admin_core/resource_page/show.rb +22 -0
  86. data/lib/admin_core/resource_router.rb +58 -0
  87. data/lib/admin_core/resource_search.rb +22 -0
  88. data/lib/admin_core/rspec/matchers.rb +18 -0
  89. data/lib/admin_core/rspec/resource_field_spec_helper.rb +54 -0
  90. data/lib/admin_core/version.rb +11 -0
  91. data/lib/admin_core/view_object/sidebar_dropdown.rb +21 -0
  92. data/lib/admin_core/view_object/sidebar_link.rb +24 -0
  93. data/lib/admin_core/view_object/sidebar_resource_link.rb +23 -0
  94. data/lib/admin_core/view_object/sidebar_title.rb +18 -0
  95. data/lib/admin_core.rb +69 -0
  96. data/lib/generators/admin_core/install_generator.rb +39 -0
  97. data/lib/generators/admin_core/resource_manager_generator.rb +166 -0
  98. data/lib/generators/admin_core/templates/admin-core.css +1 -0
  99. data/lib/generators/admin_core/templates/admin-core.js +38196 -0
  100. data/lib/generators/admin_core/templates/controller.rb.erb +4 -0
  101. data/lib/generators/admin_core/templates/initializer.rb.erb +3 -0
  102. data/lib/generators/admin_core/templates/resource_manager.rb.erb +33 -0
  103. data/lib/generators/admin_core/templates/view.html.erb +58 -0
  104. data/sample/.gitignore +21 -0
  105. data/sample/Gemfile +35 -0
  106. data/sample/Gemfile.lock +147 -0
  107. data/sample/README.md +24 -0
  108. data/sample/Rakefile +6 -0
  109. data/sample/app/assets/config/manifest.js +2 -0
  110. data/sample/app/assets/images/.keep +0 -0
  111. data/sample/app/assets/stylesheets/application.css +15 -0
  112. data/sample/app/controllers/admin/application_controller.rb +4 -0
  113. data/sample/app/controllers/admin/tweets_controller.rb +4 -0
  114. data/sample/app/controllers/admin/users_controller.rb +4 -0
  115. data/sample/app/controllers/application_controller.rb +3 -0
  116. data/sample/app/controllers/concerns/.keep +0 -0
  117. data/sample/app/helpers/application_helper.rb +2 -0
  118. data/sample/app/jobs/application_job.rb +2 -0
  119. data/sample/app/models/admin/tweet.rb +35 -0
  120. data/sample/app/models/admin/user.rb +41 -0
  121. data/sample/app/models/application_record.rb +3 -0
  122. data/sample/app/models/concerns/.keep +0 -0
  123. data/sample/app/models/tweet.rb +3 -0
  124. data/sample/app/models/user.rb +3 -0
  125. data/sample/app/views/admin/application.html.erb +64 -0
  126. data/sample/app/views/layouts/application.html.erb +13 -0
  127. data/sample/bin/bundle +3 -0
  128. data/sample/bin/rails +4 -0
  129. data/sample/bin/rake +4 -0
  130. data/sample/bin/setup +34 -0
  131. data/sample/bin/update +29 -0
  132. data/sample/config/application.rb +25 -0
  133. data/sample/config/boot.rb +3 -0
  134. data/sample/config/database.yml +25 -0
  135. data/sample/config/environment.rb +5 -0
  136. data/sample/config/environments/development.rb +42 -0
  137. data/sample/config/environments/production.rb +69 -0
  138. data/sample/config/environments/test.rb +36 -0
  139. data/sample/config/initializers/admin_core.rb +8 -0
  140. data/sample/config/initializers/application_controller_renderer.rb +6 -0
  141. data/sample/config/initializers/backtrace_silencers.rb +7 -0
  142. data/sample/config/initializers/cookies_serializer.rb +5 -0
  143. data/sample/config/initializers/filter_parameter_logging.rb +4 -0
  144. data/sample/config/initializers/inflections.rb +16 -0
  145. data/sample/config/initializers/mime_types.rb +4 -0
  146. data/sample/config/initializers/new_framework_defaults.rb +24 -0
  147. data/sample/config/initializers/session_store.rb +3 -0
  148. data/sample/config/initializers/wrap_parameters.rb +14 -0
  149. data/sample/config/locales/en.yml +23 -0
  150. data/sample/config/routes.rb +6 -0
  151. data/sample/config/secrets.yml +22 -0
  152. data/sample/config.ru +5 -0
  153. data/sample/db/migrate/20170417055257_create_users.rb +10 -0
  154. data/sample/db/migrate/20170417055412_create_tweets.rb +9 -0
  155. data/sample/db/schema.rb +31 -0
  156. data/sample/db/seeds.rb +7 -0
  157. data/sample/lib/assets/.keep +0 -0
  158. data/sample/lib/tasks/.keep +0 -0
  159. data/sample/log/.keep +0 -0
  160. data/sample/public/404.html +67 -0
  161. data/sample/public/422.html +67 -0
  162. data/sample/public/500.html +66 -0
  163. data/sample/public/apple-touch-icon-precomposed.png +0 -0
  164. data/sample/public/apple-touch-icon.png +0 -0
  165. data/sample/public/bundle.min.js +27 -0
  166. data/sample/public/bundle.min.js.map +1 -0
  167. data/sample/public/favicon.ico +0 -0
  168. data/sample/public/javascripts/admin-core.js +38196 -0
  169. data/sample/public/robots.txt +5 -0
  170. data/sample/public/stylesheets/admin-core.css +1 -0
  171. data/sample/tmp/.keep +0 -0
  172. data/sample/vendor/assets/stylesheets/.keep +0 -0
  173. metadata +368 -0
@@ -0,0 +1,114 @@
1
+ require 'action_controller'
2
+
3
+ module AdminCore
4
+ # @abstract
5
+ class BaseController < ActionController::Base
6
+ def index
7
+ respond_to do |format|
8
+ format.html do
9
+ render template: AdminCore.config.template
10
+ end
11
+ format.json do
12
+ render json: { page: AdminCore::ResourcePage::Index.new(resource_manager, params) }
13
+ end
14
+ end
15
+ end
16
+
17
+ def new
18
+ respond_to do |format|
19
+ format.html do
20
+ render template: AdminCore.config.template
21
+ end
22
+ format.json do
23
+ render json: { page: AdminCore::ResourcePage::New.new(resource_manager, params) }
24
+ end
25
+ end
26
+ end
27
+
28
+ def create
29
+ resource = resource_manager.build(params_for_create)
30
+ if resource.save
31
+ render json: { redirectTo: resource_router.show_path(resource) }
32
+ else
33
+ render_errors(resource)
34
+ end
35
+ end
36
+
37
+ def show
38
+ respond_to do |format|
39
+ format.html do
40
+ render template: AdminCore.config.template
41
+ end
42
+ format.json do
43
+ render json: { page: AdminCore::ResourcePage::Show.new(resource_manager, params) }
44
+ end
45
+ end
46
+ end
47
+
48
+ def edit
49
+ respond_to do |format|
50
+ format.html do
51
+ render template: AdminCore.config.template
52
+ end
53
+ format.json do
54
+ render json: { page: AdminCore::ResourcePage::Edit.new(resource_manager, params) }
55
+ end
56
+ end
57
+ end
58
+
59
+ def update
60
+ resource = resource_manager.find(params)
61
+ if resource.update(params_for_update)
62
+ render json: { redirectTo: resource_router.show_path(resource) }
63
+ else
64
+ render_errors(resource)
65
+ end
66
+ end
67
+
68
+ def destroy
69
+ resource = resource_manager.find(params)
70
+ if resource.destroy
71
+ render json: { redirectTo: resource_router.index_path }
72
+ else
73
+ render_errors(resource)
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ # @param resource [ActiveRecord::Base]
80
+ def render_errors(resource)
81
+ errors = {}
82
+ resource.errors.messages.keys.each do |key|
83
+ errors[key] = resource.errors.full_messages_for(key)
84
+ end
85
+ render json: { errors: errors }, status: :unprocessable_entity
86
+ end
87
+
88
+ # @return [AdminCore::BaseResourceManager]
89
+ def resource_manager
90
+ @resource_manager ||= resource_manager_class.new
91
+ end
92
+
93
+ # @return [AdminCore::ResourceRouter]
94
+ def resource_router
95
+ resource_manager_class.router
96
+ end
97
+
98
+ # @return [Class]
99
+ def resource_manager_class
100
+ resource_name = controller_path.singularize.split('/')[-1]
101
+ "#{AdminCore.config.module_name}::#{resource_name.camelize}".constantize
102
+ end
103
+
104
+ # @return [ActionController::Parameters]
105
+ def params_for_create
106
+ params.require(resource_manager.name).permit(resource_manager.permitted_field_names_for(:new))
107
+ end
108
+
109
+ # @return [ActionController::Parameters]
110
+ def params_for_update
111
+ params.require(resource_manager.name).permit(resource_manager.permitted_field_names_for(:edit))
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'resource_manager/buildable'
2
+ require_relative 'resource_manager/convert'
3
+ require_relative 'resource_manager/has_many_fields'
4
+ require_relative 'resource_manager/permission'
5
+ require_relative 'resource_manager/searchable'
6
+
7
+ module AdminCore
8
+ # @abstract
9
+ class BaseResourceManager
10
+ include AdminCore::ResourceManager::Buildable
11
+ include AdminCore::ResourceManager::Convert
12
+ include AdminCore::ResourceManager::HasManyFields
13
+ include AdminCore::ResourceManager::Searchable
14
+ include AdminCore::ResourceManager::Permission
15
+
16
+ private
17
+
18
+ # @param resource [ActiveRecord::Base]
19
+ # @return [String]
20
+ def display_resource(resource)
21
+ "#{resource.class} ##{resource.id}"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module AdminCore
2
+ # Stores AdminCore configuration information.
3
+ class Configuration
4
+ DEFAULT_MODULE_NAME = 'Admin'.freeze
5
+
6
+ attr_accessor :route_name_prefix, :module_name, :template
7
+
8
+ def module_name
9
+ @module_name ||= DEFAULT_MODULE_NAME
10
+ end
11
+
12
+ def route_name_prefix
13
+ @route_name_prefix ||= module_name.underscore
14
+ end
15
+
16
+ def template
17
+ @template ||= "#{route_name_prefix}/application"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ require 'rails'
2
+
3
+ module AdminCore
4
+ class Engine < Rails::Engine
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ module AdminCore
2
+ # Base of any errors raised by AdminCore.
3
+ class Error < StandardError
4
+ end
5
+
6
+ class ResourceManagerAlreadyRegistered < Error
7
+ end
8
+
9
+ class ResourceFieldAlreadyRegistered < Error
10
+ end
11
+
12
+ class ResourceFieldNotFound < Error
13
+ end
14
+
15
+ class InvalidResourceFieldDefinition < Error
16
+ end
17
+ end
@@ -0,0 +1,69 @@
1
+ require 'admin_core/resource_field_builder'
2
+
3
+ module AdminCore
4
+ module ResourceField
5
+ # @abstract Subclass and override {#field_value} to implement a custom resource field class.
6
+ class Base
7
+ # @return [Symbol]
8
+ def self.type
9
+ name.demodulize.underscore.to_sym
10
+ end
11
+
12
+ # @param name [Symbol]
13
+ # @return [Symbol]
14
+ def self.permitted_field_name_of(name)
15
+ name
16
+ end
17
+
18
+ def self.register
19
+ AdminCore::ResourceFieldBuilder.register(type, self)
20
+ end
21
+
22
+ # @param resource [ActiveRecord::Base]
23
+ # @param name [Symbol]
24
+ # @param options [Hash]
25
+ # @param page [Symbol] :index, :new, :show or :edit
26
+ # @raise [AdminCore::InvalidFieldDefinition]
27
+ def initialize(resource, name, options, page)
28
+ @resource = resource
29
+ @name = name
30
+ @options = options
31
+ @page = page
32
+ validate
33
+ end
34
+
35
+ # Representation of ResourceField type.
36
+ #
37
+ # @return [Hash]
38
+ def to_hash
39
+ {
40
+ type: self.class.type,
41
+ name: name,
42
+ displayName: human_attribute_name,
43
+ value: field_value,
44
+ }
45
+ end
46
+
47
+ private
48
+
49
+ attr_reader :resource, :name, :options, :page
50
+
51
+ def field_value
52
+ raise NotImplementedError
53
+ end
54
+
55
+ # Override this method to validate field definition.
56
+ #
57
+ # @raise [AdminCore::InvalidFieldDefinition]
58
+ def validate; end
59
+
60
+ def data
61
+ resource.public_send(name)
62
+ end
63
+
64
+ def human_attribute_name
65
+ resource.class.human_attribute_name(name)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,38 @@
1
+ require_relative 'base'
2
+ require_relative '../errors'
3
+
4
+ module AdminCore
5
+ module ResourceField
6
+ class BelongsTo < Base
7
+ private
8
+
9
+ def field_value
10
+ {
11
+ # Remove fields to avoid infinite field dependency loop
12
+ resource: associated_resource_manager.convert_for_index_page(associated_resource).merge(fields: []),
13
+ }
14
+ end
15
+
16
+ def validate
17
+ return if associated_resource_manager_class
18
+ raise AdminCore::InvalidResourceFieldDefinition, 'resource_manager_class option is required'
19
+ end
20
+
21
+ def associated_resource
22
+ data || associated_resource_manager.build({})
23
+ end
24
+
25
+ def associated_resource_manager
26
+ @associated_resource_manager ||= associated_resource_manager_class.new
27
+ end
28
+
29
+ def associated_resource_manager_class
30
+ options[:resource_manager_class] || AdminCore.resource_managers.find do |manager_class|
31
+ manager_class.resource_name.to_sym == name
32
+ end
33
+ end
34
+ end
35
+
36
+ AdminCore.register_resource_field(BelongsTo)
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceField
5
+ # @!attribute [r] data
6
+ # @return [Boolean]
7
+ class Boolean < Base
8
+ private
9
+
10
+ # @note Implementation for {QiitaAdmin::ResourceField::Base#field_value}
11
+ def field_value
12
+ data
13
+ end
14
+ end
15
+
16
+ AdminCore.register_resource_field(Boolean)
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceField
5
+ # @!attribute [r] data
6
+ # @return [ActiveSupport::TimeWithZone]
7
+ class Date < Base
8
+ private
9
+
10
+ # @note Implementation for {QiitaAdmin::ResourceField::Base#field_value}
11
+ def field_value
12
+ data.to_s
13
+ end
14
+ end
15
+
16
+ AdminCore.register_resource_field(Date)
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceField
5
+ # @!attribute [r] data
6
+ # @return [ActiveSupport::TimeWithZone]
7
+ class DateTime < Base
8
+ private
9
+
10
+ # @note Implementation for {QiitaAdmin::ResourceField::Base#field_value}
11
+ def field_value
12
+ data.to_s
13
+ end
14
+ end
15
+
16
+ AdminCore.register_resource_field(DateTime)
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceField
5
+ # @!attribute [r] data
6
+ # @return [String]
7
+ class Enum < Base
8
+ private
9
+
10
+ # @note Implementation for {QiitaAdmin::ResourceField::Base#field_value}
11
+ def field_value
12
+ {
13
+ value: data,
14
+ values: values,
15
+ }
16
+ end
17
+
18
+ # @return [Array<String>]
19
+ def values
20
+ options.fetch(:values, [])
21
+ end
22
+ end
23
+
24
+ AdminCore.register_resource_field(Enum)
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceField
5
+ # @!attribute [r] data
6
+ # @return [Integer, Float]
7
+ class Number < Base
8
+ private
9
+
10
+ # @note Implementation for {QiitaAdmin::ResourceField::Base#field_value}
11
+ def field_value
12
+ data
13
+ end
14
+ end
15
+
16
+ AdminCore.register_resource_field(Number)
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceField
5
+ # @!attribute [r] data
6
+ # @return [String]
7
+ class String < Base
8
+ private
9
+
10
+ # @note Implementation for {QiitaAdmin::ResourceField::Base#field_value}
11
+ def field_value
12
+ data
13
+ end
14
+ end
15
+
16
+ AdminCore.register_resource_field(String)
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceField
5
+ # @!attribute [r] data
6
+ # @return [String]
7
+ class Text < Base
8
+ private
9
+
10
+ # @note Implementation for {QiitaAdmin::ResourceField::Base#field_value}
11
+ def field_value
12
+ data.to_s[0...truncate_length]
13
+ end
14
+
15
+ # @return [Integer]
16
+ def truncate_length
17
+ options.fetch(:truncate, 50)
18
+ end
19
+ end
20
+
21
+ AdminCore.register_resource_field(Text)
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ require 'set'
2
+ require 'admin_core/errors'
3
+
4
+ module AdminCore
5
+ class ResourceFieldBuilder
6
+ # @param type [Symbol]
7
+ # @return [Class]
8
+ # @raise [AdminCore::FieldNotFound]
9
+ def self.resolve(type)
10
+ unless AdminCore.resource_field_map.key?(type)
11
+ raise AdminCore::FieldNotFound, "Unknown field: #{type}"
12
+ end
13
+ AdminCore.resource_field_map[type]
14
+ end
15
+
16
+ # @param name [Symbol]
17
+ # @param type [Symbol, Class]
18
+ # @param options [Symbol]
19
+ def initialize(name, type, options)
20
+ @name = name
21
+ @type = type
22
+ @options = options
23
+ end
24
+
25
+ # @param resource [ActiveRecord::Base]
26
+ # @param page [Symbol]
27
+ # @return [AdminCore::ResourceField::Base]
28
+ # @raise [AdminCore::FieldNotFound]
29
+ def build(resource, page)
30
+ resource_field_class.new(resource, name, options, page)
31
+ end
32
+
33
+ # @return [Symbol]
34
+ # @raise [AdminCore::FieldNotFound]
35
+ def permitted_field_name
36
+ resource_field_class.permitted_field_name_of(name)
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :name, :type, :options
42
+
43
+ # @return [Class]
44
+ def resource_field_class
45
+ @resource_field_class ||= self.class.resolve(type)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,63 @@
1
+ module AdminCore
2
+ module ResourceFilter
3
+ class Base
4
+ # @return [String]
5
+ def self.default_query_operator
6
+ 'is'
7
+ end
8
+
9
+ # @return [String]
10
+ def self.type
11
+ name.demodulize.underscore.to_sym
12
+ end
13
+
14
+ # @param resource_manager [AdminCore::BaseResourceManager]
15
+ # @param name [Symbol]
16
+ # @param options [Hash]
17
+ # @param query_operator [String]
18
+ # @param query_value [String]
19
+ def initialize(resource_manager, name, options, query_operator, query_value)
20
+ @resource_manager = resource_manager
21
+ @name = name
22
+ @options = options
23
+ @query_operator = query_operator
24
+ @query_value = query_value
25
+ end
26
+
27
+ def empty?
28
+ query_value ? query_value.empty? : true
29
+ end
30
+
31
+ def to_hash
32
+ {
33
+ type: self.class.type,
34
+ name: name,
35
+ displayName: display_name,
36
+ query: {
37
+ operator: query_operator,
38
+ value: query_value,
39
+ },
40
+ }
41
+ end
42
+
43
+ # @param relation [ActiveRecord::Relation]
44
+ # @return [ActiveRecord::Relation]
45
+ def apply(relation) # rubocop:disable Lint/UnusedMethodArgument
46
+ raise NotImplementedError
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :resource_manager, :name, :options, :query_value
52
+
53
+ # @return [String]
54
+ def display_name
55
+ resource_manager.class.resource_class.human_attribute_name(name)
56
+ end
57
+
58
+ def query_operator
59
+ @query_operator || self.class.default_query_operator
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceFilter
5
+ class Boolean < Base
6
+ # @note Implementation for {AdminCore::ResourceFilter::Base#apply}
7
+ def apply(relation)
8
+ case query_operator
9
+ when 'is'
10
+ relation.where(name => %w[true yes on 1].include?(query_value))
11
+ else
12
+ raise NotImplementedError
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceFilter
5
+ class Number < Base
6
+ def self.default_query_operator
7
+ 'equals'
8
+ end
9
+
10
+ # @note Implementation for {AdminCore::ResourceFilter::Base#apply}
11
+ def apply(relation) # rubocop:disable Metrics/AbcSize
12
+ case query_operator
13
+ when 'equals'
14
+ relation.where(name => query_value)
15
+ when 'greater_than'
16
+ relation.where(relation.arel_table[name].gt(query_value))
17
+ when 'less_than'
18
+ relation.where(relation.arel_table[name].lt(query_value))
19
+ else
20
+ raise NotImplementedError
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'base'
2
+
3
+ module AdminCore
4
+ module ResourceFilter
5
+ class String < Base
6
+ def self.default_query_operator
7
+ 'equals'
8
+ end
9
+
10
+ # @note Implementation for {AdminCore::ResourceFilter::Base#apply}
11
+ def apply(relation) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
12
+ case query_operator
13
+ when 'contains'
14
+ relation.where(relation.arel_table[name].matches("%#{query_value}%"))
15
+ when 'equals'
16
+ relation.where(name => query_value)
17
+ when 'starts_with'
18
+ relation.where(relation.arel_table[name].matches("#{query_value}%"))
19
+ when 'ends_with'
20
+ relation.where(relation.arel_table[name].matches("%#{query_value}"))
21
+ else
22
+ raise NotImplementedError, query_operator
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ module AdminCore
2
+ # @!attribute name
3
+ # @return [Symbol]
4
+ # @!attribute type
5
+ # @return [Symbol]
6
+ # @!attribute options
7
+ # @return [Symbol]
8
+ ResourceFilterBuilder = Struct.new(:name, :type, :options) do
9
+ # @param resource_manager [AdminCore::BaseResourceManager]
10
+ # @param params [ActionController::Parameters]
11
+ # @return [AdminCore::ResourceFilter::Base]
12
+ def build(resource_manager, params)
13
+ query_operator, query_value = parse(params)
14
+ resource_filter_class.new(resource_manager, name, options, query_operator, query_value)
15
+ end
16
+
17
+ private
18
+
19
+ # @return [Class]
20
+ def resource_filter_class
21
+ @resource_filter_class ||= "AdminCore::ResourceFilter::#{type.to_s.camelize}".constantize
22
+ end
23
+
24
+ def regexp
25
+ @regexp = /\A#{name}(?::(\w+))?\z/
26
+ end
27
+
28
+ def parse(params)
29
+ params.keys.each do |key|
30
+ if (match = regexp.match(key))
31
+ return [match[1] || resource_filter_class.default_query_operator, params[key]]
32
+ end
33
+ end
34
+ []
35
+ end
36
+ end
37
+ end