rails_admin_next 1.0.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.
- checksums.yaml +7 -0
- data/Gemfile +46 -0
- data/LICENSE.md +21 -0
- data/README.md +317 -0
- data/Rakefile +25 -0
- data/app/assets/javascripts/rails_admin/custom/ui.js +1 -0
- data/app/assets/stylesheets/rails_admin/framework.css +2375 -0
- data/app/assets/stylesheets/rails_admin/skin.css +472 -0
- data/app/assets/stylesheets/rails_admin/tokens.css +281 -0
- data/app/assets/stylesheets/rails_admin.css +47 -0
- data/app/controllers/rails_admin_next/application_controller.rb +98 -0
- data/app/controllers/rails_admin_next/main_controller.rb +185 -0
- data/app/helpers/rails_admin_next/application_helper.rb +254 -0
- data/app/helpers/rails_admin_next/form_builder.rb +173 -0
- data/app/helpers/rails_admin_next/main_helper.rb +63 -0
- data/app/views/layouts/rails_admin_next/_head.html.erb +29 -0
- data/app/views/layouts/rails_admin_next/_navigation.html.erb +18 -0
- data/app/views/layouts/rails_admin_next/_secondary_navigation.html.erb +27 -0
- data/app/views/layouts/rails_admin_next/_sidebar_navigation.html.erb +6 -0
- data/app/views/layouts/rails_admin_next/application.html.erb +42 -0
- data/app/views/layouts/rails_admin_next/content.html.erb +22 -0
- data/app/views/layouts/rails_admin_next/modal.js.erb +7 -0
- data/app/views/rails_admin_next/main/_dashboard_history.html.erb +46 -0
- data/app/views/rails_admin_next/main/_delete_notice.html.erb +36 -0
- data/app/views/rails_admin_next/main/_form_action_text.html.erb +2 -0
- data/app/views/rails_admin_next/main/_form_boolean.html.erb +15 -0
- data/app/views/rails_admin_next/main/_form_colorpicker.html.erb +6 -0
- data/app/views/rails_admin_next/main/_form_datetime.html.erb +14 -0
- data/app/views/rails_admin_next/main/_form_enumeration.html.erb +26 -0
- data/app/views/rails_admin_next/main/_form_field.html.erb +2 -0
- data/app/views/rails_admin_next/main/_form_file_upload.html.erb +18 -0
- data/app/views/rails_admin_next/main/_form_filtering_multiselect.html.erb +20 -0
- data/app/views/rails_admin_next/main/_form_filtering_select.html.erb +22 -0
- data/app/views/rails_admin_next/main/_form_multiple_file_upload.html.erb +21 -0
- data/app/views/rails_admin_next/main/_form_nested_many.html.erb +20 -0
- data/app/views/rails_admin_next/main/_form_nested_one.html.erb +19 -0
- data/app/views/rails_admin_next/main/_form_polymorphic_association.html.erb +24 -0
- data/app/views/rails_admin_next/main/_form_text.html.erb +2 -0
- data/app/views/rails_admin_next/main/_pagination.html.erb +54 -0
- data/app/views/rails_admin_next/main/_submit_buttons.html.erb +26 -0
- data/app/views/rails_admin_next/main/bulk_delete.html.erb +19 -0
- data/app/views/rails_admin_next/main/dashboard.html.erb +64 -0
- data/app/views/rails_admin_next/main/delete.html.erb +21 -0
- data/app/views/rails_admin_next/main/edit.html.erb +3 -0
- data/app/views/rails_admin_next/main/export.html.erb +149 -0
- data/app/views/rails_admin_next/main/history.html.erb +80 -0
- data/app/views/rails_admin_next/main/index.html.erb +186 -0
- data/app/views/rails_admin_next/main/new.html.erb +3 -0
- data/app/views/rails_admin_next/main/show.html.erb +30 -0
- data/config/brakeman.ignore +145 -0
- data/config/importmap.rails_admin.rb +29 -0
- data/config/initializers/active_record_extensions.rb +21 -0
- data/config/locales/rails_admin_next.en.yml +158 -0
- data/config/routes.rb +14 -0
- data/lib/generators/rails_admin_next/install_generator.rb +39 -0
- data/lib/generators/rails_admin_next/templates/initializer.erb +40 -0
- data/lib/generators/rails_admin_next/utils.rb +21 -0
- data/lib/rails_admin_next/abstract_model.rb +266 -0
- data/lib/rails_admin_next/adapters/active_record/association.rb +130 -0
- data/lib/rails_admin_next/adapters/active_record/object_extension.rb +13 -0
- data/lib/rails_admin_next/adapters/active_record/property.rb +58 -0
- data/lib/rails_admin_next/adapters/active_record.rb +371 -0
- data/lib/rails_admin_next/config/actions/base.rb +160 -0
- data/lib/rails_admin_next/config/actions/bulk_delete.rb +67 -0
- data/lib/rails_admin_next/config/actions/dashboard.rb +62 -0
- data/lib/rails_admin_next/config/actions/delete.rb +58 -0
- data/lib/rails_admin_next/config/actions/edit.rb +56 -0
- data/lib/rails_admin_next/config/actions/export.rb +47 -0
- data/lib/rails_admin_next/config/actions/history_index.rb +40 -0
- data/lib/rails_admin_next/config/actions/history_show.rb +40 -0
- data/lib/rails_admin_next/config/actions/index.rb +108 -0
- data/lib/rails_admin_next/config/actions/new.rb +69 -0
- data/lib/rails_admin_next/config/actions/show.rb +36 -0
- data/lib/rails_admin_next/config/actions/show_in_app.rb +37 -0
- data/lib/rails_admin_next/config/actions.rb +122 -0
- data/lib/rails_admin_next/config/configurable.rb +107 -0
- data/lib/rails_admin_next/config/const_load_suppressor.rb +78 -0
- data/lib/rails_admin_next/config/fields/association.rb +169 -0
- data/lib/rails_admin_next/config/fields/base.rb +391 -0
- data/lib/rails_admin_next/config/fields/collection_association.rb +90 -0
- data/lib/rails_admin_next/config/fields/factories/action_text.rb +14 -0
- data/lib/rails_admin_next/config/fields/factories/active_storage.rb +34 -0
- data/lib/rails_admin_next/config/fields/factories/association.rb +32 -0
- data/lib/rails_admin_next/config/fields/factories/encrypted_password.rb +28 -0
- data/lib/rails_admin_next/config/fields/factories/enum.rb +23 -0
- data/lib/rails_admin_next/config/fields/factories/password.rb +19 -0
- data/lib/rails_admin_next/config/fields/group.rb +77 -0
- data/lib/rails_admin_next/config/fields/singular_association.rb +62 -0
- data/lib/rails_admin_next/config/fields/types/action_text.rb +20 -0
- data/lib/rails_admin_next/config/fields/types/active_record_enum.rb +62 -0
- data/lib/rails_admin_next/config/fields/types/active_storage.rb +70 -0
- data/lib/rails_admin_next/config/fields/types/all.rb +32 -0
- data/lib/rails_admin_next/config/fields/types/belongs_to_association.rb +48 -0
- data/lib/rails_admin_next/config/fields/types/boolean.rb +70 -0
- data/lib/rails_admin_next/config/fields/types/citext.rb +15 -0
- data/lib/rails_admin_next/config/fields/types/color.rb +43 -0
- data/lib/rails_admin_next/config/fields/types/date.rb +38 -0
- data/lib/rails_admin_next/config/fields/types/datetime.rb +79 -0
- data/lib/rails_admin_next/config/fields/types/decimal.rb +23 -0
- data/lib/rails_admin_next/config/fields/types/enum.rb +52 -0
- data/lib/rails_admin_next/config/fields/types/file_upload.rb +87 -0
- data/lib/rails_admin_next/config/fields/types/float.rb +23 -0
- data/lib/rails_admin_next/config/fields/types/has_and_belongs_to_many_association.rb +16 -0
- data/lib/rails_admin_next/config/fields/types/has_many_association.rb +16 -0
- data/lib/rails_admin_next/config/fields/types/has_one_association.rb +35 -0
- data/lib/rails_admin_next/config/fields/types/hidden.rb +31 -0
- data/lib/rails_admin_next/config/fields/types/inet.rb +15 -0
- data/lib/rails_admin_next/config/fields/types/integer.rb +20 -0
- data/lib/rails_admin_next/config/fields/types/json.rb +37 -0
- data/lib/rails_admin_next/config/fields/types/multiple_active_storage.rb +82 -0
- data/lib/rails_admin_next/config/fields/types/multiple_file_upload.rb +134 -0
- data/lib/rails_admin_next/config/fields/types/numeric.rb +24 -0
- data/lib/rails_admin_next/config/fields/types/password.rb +45 -0
- data/lib/rails_admin_next/config/fields/types/polymorphic_association.rb +118 -0
- data/lib/rails_admin_next/config/fields/types/serialized.rb +28 -0
- data/lib/rails_admin_next/config/fields/types/string.rb +50 -0
- data/lib/rails_admin_next/config/fields/types/string_like.rb +25 -0
- data/lib/rails_admin_next/config/fields/types/text.rb +28 -0
- data/lib/rails_admin_next/config/fields/types/time.rb +39 -0
- data/lib/rails_admin_next/config/fields/types/timestamp.rb +16 -0
- data/lib/rails_admin_next/config/fields/types/uuid.rb +15 -0
- data/lib/rails_admin_next/config/fields/types.rb +29 -0
- data/lib/rails_admin_next/config/fields.rb +88 -0
- data/lib/rails_admin_next/config/groupable.rb +20 -0
- data/lib/rails_admin_next/config/has_description.rb +14 -0
- data/lib/rails_admin_next/config/has_fields.rb +144 -0
- data/lib/rails_admin_next/config/has_groups.rb +27 -0
- data/lib/rails_admin_next/config/hideable.rb +30 -0
- data/lib/rails_admin_next/config/inspectable.rb +39 -0
- data/lib/rails_admin_next/config/lazy_model.rb +74 -0
- data/lib/rails_admin_next/config/model.rb +126 -0
- data/lib/rails_admin_next/config/proxyable/proxy.rb +42 -0
- data/lib/rails_admin_next/config/proxyable.rb +26 -0
- data/lib/rails_admin_next/config/sections/base.rb +36 -0
- data/lib/rails_admin_next/config/sections/create.rb +13 -0
- data/lib/rails_admin_next/config/sections/edit.rb +13 -0
- data/lib/rails_admin_next/config/sections/export.rb +13 -0
- data/lib/rails_admin_next/config/sections/list.rb +63 -0
- data/lib/rails_admin_next/config/sections/modal.rb +12 -0
- data/lib/rails_admin_next/config/sections/nested.rb +12 -0
- data/lib/rails_admin_next/config/sections/show.rb +12 -0
- data/lib/rails_admin_next/config/sections/update.rb +12 -0
- data/lib/rails_admin_next/config/sections.rb +39 -0
- data/lib/rails_admin_next/config.rb +436 -0
- data/lib/rails_admin_next/engine.rb +91 -0
- data/lib/rails_admin_next/extension.rb +35 -0
- data/lib/rails_admin_next/extensions/cancancan/authorization_adapter.rb +90 -0
- data/lib/rails_admin_next/extensions/cancancan.rb +5 -0
- data/lib/rails_admin_next/extensions/controller_extension.rb +8 -0
- data/lib/rails_admin_next/extensions/paper_trail/auditing_adapter.rb +192 -0
- data/lib/rails_admin_next/extensions/paper_trail.rb +5 -0
- data/lib/rails_admin_next/extensions/pundit/authorization_adapter.rb +72 -0
- data/lib/rails_admin_next/extensions/pundit.rb +5 -0
- data/lib/rails_admin_next/extensions/url_for_extension.rb +15 -0
- data/lib/rails_admin_next/icons.rb +143 -0
- data/lib/rails_admin_next/support/composite_keys_serializer.rb +15 -0
- data/lib/rails_admin_next/support/csv_converter.rb +100 -0
- data/lib/rails_admin_next/support/hash_helper.rb +31 -0
- data/lib/rails_admin_next/support/paginated_collection.rb +79 -0
- data/lib/rails_admin_next/version.rb +17 -0
- data/lib/rails_admin_next.rb +72 -0
- data/lib/tasks/rails_admin.rake +40 -0
- data/src/rails_admin/application.js +15 -0
- data/src/rails_admin/base.js +12 -0
- data/src/rails_admin/controllers/alert_controller.js +28 -0
- data/src/rails_admin/controllers/collapse_controller.js +16 -0
- data/src/rails_admin/controllers/dropdown_controller.js +110 -0
- data/src/rails_admin/controllers/feedback_controller.js +73 -0
- data/src/rails_admin/controllers/filter_box_controller.js +346 -0
- data/src/rails_admin/controllers/filtering_multiselect_controller.js +386 -0
- data/src/rails_admin/controllers/filtering_select_controller.js +509 -0
- data/src/rails_admin/controllers/index.js +31 -0
- data/src/rails_admin/controllers/modal_controller.js +142 -0
- data/src/rails_admin/controllers/nested_form_controller.js +117 -0
- data/src/rails_admin/controllers/polymorphic_controller.js +26 -0
- data/src/rails_admin/controllers/remote_form_controller.js +173 -0
- data/src/rails_admin/controllers/sidescroll_controller.js +23 -0
- data/src/rails_admin/dom-ready.js +20 -0
- data/src/rails_admin/dom.js +19 -0
- data/src/rails_admin/i18n.js +20 -0
- data/src/rails_admin/icons.js +64 -0
- data/src/rails_admin/interactions.js +221 -0
- data/src/rails_admin/select_query.js +65 -0
- metadata +346 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_admin_next/config/proxyable"
|
|
4
|
+
require "rails_admin_next/config/configurable"
|
|
5
|
+
require "rails_admin_next/config/hideable"
|
|
6
|
+
require "rails_admin_next/config/groupable"
|
|
7
|
+
require "rails_admin_next/config/inspectable"
|
|
8
|
+
|
|
9
|
+
module RailsAdminNext
|
|
10
|
+
module Config
|
|
11
|
+
module Fields
|
|
12
|
+
class Base # rubocop:disable Metrics/ClassLength
|
|
13
|
+
include RailsAdminNext::Config::Proxyable
|
|
14
|
+
include RailsAdminNext::Config::Configurable
|
|
15
|
+
include RailsAdminNext::Config::Hideable
|
|
16
|
+
include RailsAdminNext::Config::Groupable
|
|
17
|
+
include RailsAdminNext::Config::Inspectable
|
|
18
|
+
|
|
19
|
+
attr_reader :name, :properties, :abstract_model, :parent, :root
|
|
20
|
+
attr_accessor :defined, :order, :section
|
|
21
|
+
|
|
22
|
+
NAMED_INSTANCE_VARIABLES = %i[
|
|
23
|
+
@parent @root @section @children_fields_registered
|
|
24
|
+
@associated_model_config @group
|
|
25
|
+
].freeze
|
|
26
|
+
|
|
27
|
+
def initialize(parent, name, properties)
|
|
28
|
+
@parent = parent
|
|
29
|
+
@root = parent.root
|
|
30
|
+
|
|
31
|
+
@abstract_model = parent.abstract_model
|
|
32
|
+
@defined = false
|
|
33
|
+
@name = name.to_sym
|
|
34
|
+
@order = 0
|
|
35
|
+
@properties = properties
|
|
36
|
+
@section = parent
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
register_instance_option :css_class do
|
|
40
|
+
"#{name}_field"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def type_css_class
|
|
44
|
+
"#{type}_type"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def virtual?
|
|
48
|
+
properties.blank?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
register_instance_option :column_width do
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
register_instance_option :sticky? do
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
register_instance_option :sortable do
|
|
60
|
+
!virtual? || children_fields.first || false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def sort_column
|
|
64
|
+
if sortable == true
|
|
65
|
+
"#{abstract_model.quoted_table_name}.#{abstract_model.quote_column_name(name)}"
|
|
66
|
+
elsif (sortable.is_a?(String) || sortable.is_a?(Symbol)) && sortable.to_s.include?(".") # just provide sortable, don't do anything smart
|
|
67
|
+
sortable
|
|
68
|
+
elsif sortable.is_a?(Hash) # just join sortable hash, don't do anything smart
|
|
69
|
+
"#{sortable.keys.first}.#{sortable.values.first}"
|
|
70
|
+
elsif association? # use column on target table
|
|
71
|
+
"#{associated_model_config.abstract_model.quoted_table_name}.#{abstract_model.quote_column_name(sortable)}"
|
|
72
|
+
else # use described column in the field conf.
|
|
73
|
+
"#{abstract_model.quoted_table_name}.#{abstract_model.quote_column_name(sortable)}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
register_instance_option :searchable do
|
|
78
|
+
!virtual? || children_fields.first || false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
register_instance_option :search_operator do
|
|
82
|
+
RailsAdminNext::Config.default_search_operator
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
register_instance_option :queryable? do
|
|
86
|
+
!virtual?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
register_instance_option :filterable? do
|
|
90
|
+
!!searchable
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
register_instance_option :filter_operators do
|
|
94
|
+
[]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
register_instance_option :default_filter_operator do
|
|
98
|
+
nil
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def filter_options
|
|
102
|
+
{
|
|
103
|
+
label: label,
|
|
104
|
+
name: name,
|
|
105
|
+
operator: default_filter_operator,
|
|
106
|
+
operators: filter_operators,
|
|
107
|
+
type: type
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# serials and dates are reversed in list, which is more natural (last modified items first).
|
|
112
|
+
register_instance_option :sort_reverse? do
|
|
113
|
+
false
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# list of columns I should search for that field [{ column: 'table_name.column', type: field.type }, {..}]
|
|
117
|
+
register_instance_option :searchable_columns do
|
|
118
|
+
@searchable_columns ||=
|
|
119
|
+
case searchable
|
|
120
|
+
when true
|
|
121
|
+
[{column: "#{abstract_model.table_name}.#{name}", type: type}]
|
|
122
|
+
when false
|
|
123
|
+
[]
|
|
124
|
+
when :all # valid only for associations
|
|
125
|
+
table_name = associated_model_config.abstract_model.table_name
|
|
126
|
+
associated_model_config.list.fields.collect { |f| {column: "#{table_name}.#{f.name}", type: f.type} }
|
|
127
|
+
else
|
|
128
|
+
[searchable].flatten.collect do |f|
|
|
129
|
+
if f.is_a?(String) && f.include?(".") # table_name.column
|
|
130
|
+
table_name, column = f.split "."
|
|
131
|
+
type = nil
|
|
132
|
+
elsif f.is_a?(Hash) # <Model|table_name> => <attribute|column>
|
|
133
|
+
am = AbstractModel.new(f.keys.first) if f.keys.first.is_a?(Class)
|
|
134
|
+
table_name = am&.table_name || f.keys.first
|
|
135
|
+
column = f.values.first
|
|
136
|
+
property = am&.properties&.detect { |p| p.name == f.values.first.to_sym }
|
|
137
|
+
type = property&.type
|
|
138
|
+
else # <attribute|column>
|
|
139
|
+
am = (association? ? associated_model_config.abstract_model : abstract_model)
|
|
140
|
+
table_name = am.table_name
|
|
141
|
+
column = f
|
|
142
|
+
property = am.properties.detect { |p| p.name == f.to_sym }
|
|
143
|
+
type = property&.type
|
|
144
|
+
end
|
|
145
|
+
{column: "#{table_name}.#{column}", type: type || :string}
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
register_instance_option :formatted_value do
|
|
151
|
+
value
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# output for pretty printing (show, list)
|
|
155
|
+
register_instance_option :pretty_value do
|
|
156
|
+
formatted_value.presence || " - "
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# output for printing in export view (developers beware: no bindings[:view] and no data!)
|
|
160
|
+
register_instance_option :export_value do
|
|
161
|
+
pretty_value
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Accessor for field's help text displayed below input field.
|
|
165
|
+
register_instance_option :help do
|
|
166
|
+
(@help ||= {})[::I18n.locale] ||= generic_field_help
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
register_instance_option :html_attributes do
|
|
170
|
+
{
|
|
171
|
+
required: required?
|
|
172
|
+
}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
register_instance_option :default_value do
|
|
176
|
+
nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Accessor for field's label.
|
|
180
|
+
#
|
|
181
|
+
# @see RailsAdminNext::AbstractModel.properties
|
|
182
|
+
register_instance_option :label do
|
|
183
|
+
(@label ||= {})[::I18n.locale] ||= abstract_model.model.human_attribute_name name
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
register_instance_option :hint do
|
|
187
|
+
@hint ||= ""
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Accessor for field's maximum length per database.
|
|
191
|
+
#
|
|
192
|
+
# @see RailsAdminNext::AbstractModel.properties
|
|
193
|
+
register_instance_option :length do
|
|
194
|
+
@length ||= properties&.length
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Accessor for field's length restrictions per validations
|
|
198
|
+
#
|
|
199
|
+
register_instance_option :valid_length do
|
|
200
|
+
@valid_length ||= abstract_model.model.validators_on(name).detect { |v| v.kind == :length }.try(&:options) || {}
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
register_instance_option :partial do
|
|
204
|
+
:form_field
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Accessor for whether this is field is mandatory.
|
|
208
|
+
#
|
|
209
|
+
# @see RailsAdminNext::AbstractModel.properties
|
|
210
|
+
register_instance_option :required? do
|
|
211
|
+
context =
|
|
212
|
+
if bindings && bindings[:object]
|
|
213
|
+
bindings[:object].persisted? ? :update : :create
|
|
214
|
+
else
|
|
215
|
+
:nil
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
(@required ||= {})[context] ||= !!([name] + children_fields).uniq.detect do |column_name|
|
|
219
|
+
abstract_model.model.validators_on(column_name).detect do |v|
|
|
220
|
+
!(v.options[:allow_nil] || v.options[:allow_blank]) &&
|
|
221
|
+
%i[presence numericality attachment_presence].include?(v.kind) &&
|
|
222
|
+
(v.options[:on] == context || v.options[:on].blank?) &&
|
|
223
|
+
v.options[:if].blank? && v.options[:unless].blank?
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Accessor for whether this is a serial field (aka. primary key, identifier).
|
|
229
|
+
#
|
|
230
|
+
# @see RailsAdminNext::AbstractModel.properties
|
|
231
|
+
register_instance_option :serial? do
|
|
232
|
+
properties&.serial?
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
register_instance_option :view_helper do
|
|
236
|
+
:text_field
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
register_instance_option :read_only? do
|
|
240
|
+
!editable?
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# init status in the view
|
|
244
|
+
register_instance_option :active? do
|
|
245
|
+
false
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
register_instance_option :visible? do
|
|
249
|
+
returned = true
|
|
250
|
+
(RailsAdminNext.config.default_hidden_fields || {}).each do |section, fields|
|
|
251
|
+
next unless self.section.is_a?("RailsAdminNext::Config::Sections::#{section.to_s.camelize}".constantize)
|
|
252
|
+
|
|
253
|
+
returned = false if fields.include?(name)
|
|
254
|
+
end
|
|
255
|
+
returned
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# columns mapped (belongs_to, active_storage, etc.). First one is used for searching/sorting by default
|
|
259
|
+
register_instance_option :children_fields do
|
|
260
|
+
[]
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
register_instance_option :eager_load do
|
|
264
|
+
false
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
register_deprecated_instance_option :eager_load?, :eager_load
|
|
268
|
+
|
|
269
|
+
def eager_load_values
|
|
270
|
+
case eager_load
|
|
271
|
+
when true
|
|
272
|
+
[name]
|
|
273
|
+
when false, nil
|
|
274
|
+
[]
|
|
275
|
+
else
|
|
276
|
+
Array.wrap(eager_load)
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
register_instance_option :render do
|
|
281
|
+
bindings[:view].render partial: "rails_admin_next/main/#{partial}", locals: {field: self, form: bindings[:form]}
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def editable?
|
|
285
|
+
!((@properties && @properties.read_only?) || (bindings[:object] && bindings[:object].readonly?))
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Is this an association
|
|
289
|
+
def association?
|
|
290
|
+
is_a?(RailsAdminNext::Config::Fields::Association)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Reader for validation errors of the bound object
|
|
294
|
+
def errors
|
|
295
|
+
([name] + children_fields).uniq.collect do |column_name|
|
|
296
|
+
bindings[:object].errors[column_name]
|
|
297
|
+
end.uniq.flatten
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Reader whether field is optional.
|
|
301
|
+
#
|
|
302
|
+
# @see RailsAdminNext::Config::Fields::Base.register_instance_option :required?
|
|
303
|
+
def optional?
|
|
304
|
+
!required?
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Inverse accessor whether this field is required.
|
|
308
|
+
#
|
|
309
|
+
# @see RailsAdminNext::Config::Fields::Base.register_instance_option :required?
|
|
310
|
+
def optional(state = nil, &block)
|
|
311
|
+
if !state.nil? || block
|
|
312
|
+
required state.nil? ? proc { instance_eval(&block) == false } : state == false
|
|
313
|
+
else
|
|
314
|
+
optional?
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Writer to make field optional.
|
|
319
|
+
#
|
|
320
|
+
# @see RailsAdminNext::Config::Fields::Base.optional
|
|
321
|
+
def optional=(state)
|
|
322
|
+
optional(state)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Reader for field's type
|
|
326
|
+
def type
|
|
327
|
+
@type ||= self.class.name.to_s.demodulize.underscore.to_sym
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Reader for field's value
|
|
331
|
+
def value
|
|
332
|
+
bindings[:object].safe_send(name)
|
|
333
|
+
rescue NoMethodError => e
|
|
334
|
+
raise e.exception <<~ERROR
|
|
335
|
+
#{e.message}
|
|
336
|
+
If you want to use a RailsAdminNext virtual field(= a field without corresponding instance method),
|
|
337
|
+
you should declare 'formatted_value' in the field definition.
|
|
338
|
+
field :#{name} do
|
|
339
|
+
formatted_value{ bindings[:object].call_some_method }
|
|
340
|
+
end
|
|
341
|
+
ERROR
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Reader for nested attributes
|
|
345
|
+
register_instance_option :nested_form do
|
|
346
|
+
false
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Allowed methods for the field in forms
|
|
350
|
+
register_instance_option :allowed_methods do
|
|
351
|
+
[method_name]
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def generic_help
|
|
355
|
+
"#{required? ? I18n.translate("admin.form.required") : I18n.translate("admin.form.optional")}. "
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def generic_field_help
|
|
359
|
+
model = abstract_model.model_name.underscore
|
|
360
|
+
model_lookup = :"admin.help.#{model}.#{name}"
|
|
361
|
+
translated = I18n.translate(model_lookup, help: generic_help, default: [generic_help])
|
|
362
|
+
(translated.is_a?(Hash) ? translated.to_a.first[1] : translated).html_safe
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def parse_value(value)
|
|
366
|
+
value
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def parse_input(_params)
|
|
370
|
+
# overridden
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def inverse_of
|
|
374
|
+
nil
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def method_name
|
|
378
|
+
name
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def form_default_value
|
|
382
|
+
(default_value if bindings[:object].new_record? && value.nil?)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def form_value
|
|
386
|
+
form_default_value.nil? ? formatted_value : form_default_value
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_admin_next/config/fields/association"
|
|
4
|
+
|
|
5
|
+
module RailsAdminNext
|
|
6
|
+
module Config
|
|
7
|
+
module Fields
|
|
8
|
+
class CollectionAssociation < Association
|
|
9
|
+
# orderable associated objects
|
|
10
|
+
register_instance_option :orderable do
|
|
11
|
+
false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
register_instance_option :partial do
|
|
15
|
+
nested_form ? :form_nested_many : :form_filtering_multiselect
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def collection(scope = nil)
|
|
19
|
+
if scope
|
|
20
|
+
super
|
|
21
|
+
elsif associated_collection_cache_all
|
|
22
|
+
selected = selected_ids
|
|
23
|
+
i = 0
|
|
24
|
+
super.sort_by { |a| [selected.index(a[1]) || selected.size, i += 1] }
|
|
25
|
+
else
|
|
26
|
+
value.map { |o| [o.send(associated_object_label_method), format_key(o.send(associated_primary_key))] }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def associated_prepopulate_params
|
|
31
|
+
{associated_model_config.abstract_model.param_key => {association.foreign_key => bindings[:object].try(:id)}}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def multiple?
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def selected_ids
|
|
39
|
+
value.map { |s| format_key(s.send(associated_primary_key)).to_s }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def parse_input(params)
|
|
43
|
+
return unless associated_model_config.abstract_model.primary_key.is_a?(Array)
|
|
44
|
+
|
|
45
|
+
if nested_form
|
|
46
|
+
params[method_name].each_value do |value|
|
|
47
|
+
value[:id] = associated_model_config.abstract_model.parse_id(value[:id])
|
|
48
|
+
end
|
|
49
|
+
elsif params[method_name].is_a?(Array)
|
|
50
|
+
params[method_name] = params[method_name].map { |key| associated_model_config.abstract_model.parse_id(key) if key.present? }.compact
|
|
51
|
+
if params[method_name].empty?
|
|
52
|
+
# Workaround for Arel::Visitors::UnsupportedVisitError in #ids_writer, until https://github.com/rails/rails/pull/51116 is in place
|
|
53
|
+
params.delete(method_name)
|
|
54
|
+
params[name] = []
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def form_default_value
|
|
60
|
+
(default_value if bindings[:object].new_record? && value.empty?)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def form_value
|
|
64
|
+
form_default_value.nil? ? selected_ids : form_default_value
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def widget_options
|
|
68
|
+
{
|
|
69
|
+
xhr: !associated_collection_cache_all,
|
|
70
|
+
"edit-url": ((inline_edit && bindings[:view].authorized?(:edit, associated_model_config.abstract_model)) ? bindings[:view].edit_path(model_name: associated_model_config.abstract_model.to_param, id: "__ID__") : ""),
|
|
71
|
+
remote_source: bindings[:view].index_path(associated_model_config.abstract_model, source_object_id: abstract_model.format_id(bindings[:object].id), source_abstract_model: abstract_model.to_param, associated_collection: name, current_action: bindings[:view].current_action, compact: true),
|
|
72
|
+
scopeBy: dynamic_scope_relationships,
|
|
73
|
+
sortable: !!orderable,
|
|
74
|
+
removable: !!removable,
|
|
75
|
+
cacheAll: !!associated_collection_cache_all,
|
|
76
|
+
regional: {
|
|
77
|
+
add: ::I18n.t("admin.misc.add_new"),
|
|
78
|
+
chooseAll: ::I18n.t("admin.misc.chose_all"),
|
|
79
|
+
clearAll: ::I18n.t("admin.misc.clear_all"),
|
|
80
|
+
down: ::I18n.t("admin.misc.down"),
|
|
81
|
+
remove: ::I18n.t("admin.misc.remove"),
|
|
82
|
+
search: ::I18n.t("admin.misc.search"),
|
|
83
|
+
up: ::I18n.t("admin.misc.up")
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_admin_next/config/fields"
|
|
4
|
+
require "rails_admin_next/config/fields/types"
|
|
5
|
+
|
|
6
|
+
RailsAdminNext::Config::Fields.register_factory do |parent, properties, fields|
|
|
7
|
+
if defined?(::ActionText) && properties.try(:association?) && (match = /\Arich_text_(.+)\Z/.match properties.name) && properties.klass.to_s == "ActionText::RichText"
|
|
8
|
+
field = RailsAdminNext::Config::Fields::Types.load(:action_text).new(parent, match[1], properties)
|
|
9
|
+
fields << field
|
|
10
|
+
true
|
|
11
|
+
else
|
|
12
|
+
false
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_admin_next/config/fields"
|
|
4
|
+
require "rails_admin_next/config/fields/types"
|
|
5
|
+
require "rails_admin_next/config/fields/types/file_upload"
|
|
6
|
+
|
|
7
|
+
RailsAdminNext::Config::Fields.register_factory do |parent, properties, fields|
|
|
8
|
+
if defined?(::ActiveStorage) && properties.try(:association?) && (match = /\A(.+)_attachments?\Z/.match properties.name) && properties.klass.to_s == "ActiveStorage::Attachment"
|
|
9
|
+
name = match[1]
|
|
10
|
+
field = RailsAdminNext::Config::Fields::Types.load(
|
|
11
|
+
(properties.type == :has_many) ? :multiple_active_storage : :active_storage
|
|
12
|
+
).new(parent, name, properties)
|
|
13
|
+
fields << field
|
|
14
|
+
associations =
|
|
15
|
+
if properties.type == :has_many
|
|
16
|
+
[:"#{name}_attachments", :"#{name}_blobs"]
|
|
17
|
+
else
|
|
18
|
+
[:"#{name}_attachment", :"#{name}_blob"]
|
|
19
|
+
end
|
|
20
|
+
children_fields = associations.map do |child_name|
|
|
21
|
+
child_association = parent.abstract_model.associations.detect { |p| p.name.to_sym == child_name }
|
|
22
|
+
next unless child_association
|
|
23
|
+
|
|
24
|
+
child_field = fields.detect { |f| f.name == child_name } || RailsAdminNext::Config::Fields.default_factory.call(parent, child_association, fields)
|
|
25
|
+
child_field.hide unless field == child_field
|
|
26
|
+
child_field.filterable(false) unless field == child_field
|
|
27
|
+
child_field.name
|
|
28
|
+
end.flatten.compact
|
|
29
|
+
field.children_fields(children_fields)
|
|
30
|
+
true
|
|
31
|
+
else
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_admin_next/config/fields"
|
|
4
|
+
require "rails_admin_next/config/fields/types"
|
|
5
|
+
require "rails_admin_next/config/fields/types/belongs_to_association"
|
|
6
|
+
|
|
7
|
+
RailsAdminNext::Config::Fields.register_factory do |parent, properties, fields|
|
|
8
|
+
parent.abstract_model.associations.filter { |a| Array(a.foreign_key).include?(properties.name) && %i[belongs_to has_and_belongs_to_many].include?(a.type) }.each do |association|
|
|
9
|
+
field = RailsAdminNext::Config::Fields::Types.load(association.field_type).new(parent, association.name, association)
|
|
10
|
+
fields << field
|
|
11
|
+
|
|
12
|
+
child_columns = []
|
|
13
|
+
possible_field_names = if association.polymorphic?
|
|
14
|
+
%i[foreign_key foreign_type foreign_inverse_of]
|
|
15
|
+
else
|
|
16
|
+
[:foreign_key]
|
|
17
|
+
end.flat_map { |k| Array(association.send(k)) }.compact
|
|
18
|
+
|
|
19
|
+
parent.abstract_model.properties.select { |p| possible_field_names.include? p.name }.each do |column|
|
|
20
|
+
child_field = fields.detect { |f| f.name.to_s == column.name.to_s }
|
|
21
|
+
child_field ||= RailsAdminNext::Config::Fields.default_factory.call(parent, column, fields)
|
|
22
|
+
child_columns << child_field
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
child_columns.each do |child_column|
|
|
26
|
+
child_column.hide
|
|
27
|
+
child_column.filterable(false)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
field.children_fields child_columns.collect(&:name)
|
|
31
|
+
end.any?
|
|
32
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_admin_next/config/fields"
|
|
4
|
+
require "rails_admin_next/config/fields/types"
|
|
5
|
+
require "rails_admin_next/config/fields/types/password"
|
|
6
|
+
|
|
7
|
+
# Register a custom field factory for models with an encrypted_password column (e.g. Devise, has_secure_password variants)
|
|
8
|
+
RailsAdminNext::Config::Fields.register_factory do |parent, properties, fields|
|
|
9
|
+
if properties.name == :encrypted_password
|
|
10
|
+
extensions = %i[password_salt reset_password_token remember_token]
|
|
11
|
+
fields << RailsAdminNext::Config::Fields::Types.load(:password).new(parent, :password, properties)
|
|
12
|
+
fields << RailsAdminNext::Config::Fields::Types.load(:password).new(parent, :password_confirmation, properties)
|
|
13
|
+
extensions.each do |ext|
|
|
14
|
+
properties = parent.abstract_model.properties.detect { |p| ext == p.name }
|
|
15
|
+
next unless properties
|
|
16
|
+
|
|
17
|
+
field = fields.detect { |f| f.name == ext }
|
|
18
|
+
unless field
|
|
19
|
+
RailsAdminNext::Config::Fields.default_factory.call(parent, properties, fields)
|
|
20
|
+
field = fields.last
|
|
21
|
+
end
|
|
22
|
+
field.hide
|
|
23
|
+
end
|
|
24
|
+
true
|
|
25
|
+
else
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_admin_next/config/fields"
|
|
4
|
+
require "rails_admin_next/config/fields/types/enum"
|
|
5
|
+
require "rails_admin_next/config/fields/types/active_record_enum"
|
|
6
|
+
|
|
7
|
+
RailsAdminNext::Config::Fields.register_factory do |parent, properties, fields|
|
|
8
|
+
model = parent.abstract_model.model
|
|
9
|
+
method_name = "#{properties.name}_enum"
|
|
10
|
+
|
|
11
|
+
# NOTICE: _method_name could be `to_enum` and this method defined in Object.
|
|
12
|
+
if !Object.respond_to?(method_name) &&
|
|
13
|
+
(model.respond_to?(method_name) ||
|
|
14
|
+
model.method_defined?(method_name))
|
|
15
|
+
fields << RailsAdminNext::Config::Fields::Types::Enum.new(parent, properties.name, properties)
|
|
16
|
+
true
|
|
17
|
+
elsif model.respond_to?(:defined_enums) && model.defined_enums[properties.name.to_s]
|
|
18
|
+
fields << RailsAdminNext::Config::Fields::Types::ActiveRecordEnum.new(parent, properties.name, properties)
|
|
19
|
+
true
|
|
20
|
+
else
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_admin_next/config/fields"
|
|
4
|
+
require "rails_admin_next/config/fields/types/password"
|
|
5
|
+
|
|
6
|
+
# Register a custom field factory for properties named as password. More property
|
|
7
|
+
# names can be registered in RailsAdminNext::Config::Fields::Password.column_names
|
|
8
|
+
# array.
|
|
9
|
+
#
|
|
10
|
+
# @see RailsAdminNext::Config::Fields::Types::Password.column_names
|
|
11
|
+
# @see RailsAdminNext::Config::Fields.register_factory
|
|
12
|
+
RailsAdminNext::Config::Fields.register_factory do |parent, properties, fields|
|
|
13
|
+
if [:password].include?(properties.name)
|
|
14
|
+
fields << RailsAdminNext::Config::Fields::Types::Password.new(parent, properties.name, properties)
|
|
15
|
+
true
|
|
16
|
+
else
|
|
17
|
+
false
|
|
18
|
+
end
|
|
19
|
+
end
|