motor-admin 0.1.64 → 0.1.70

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,3 +22,4 @@ require_relative './active_record_utils/active_storage_links_extension'
22
22
  require_relative './active_record_utils/active_storage_blob_patch'
23
23
  require_relative './active_record_utils/active_record_filter_patch'
24
24
  require_relative './active_record_utils/active_record_connection_column_patch'
25
+ require_relative './active_record_utils/action_text_attribute_patch'
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(ActionText::Attribute)
4
+ ActionText::Attribute::ClassMethods.prepend(Module.new do
5
+ # rubocop:disable Naming/PredicateName
6
+ def has_rich_text(*args)
7
+ super
8
+
9
+ name = args.first
10
+
11
+ alias_method :"#{name}_body=", :"#{name}="
12
+
13
+ define_method(:"#{name}_body") do
14
+ send(name).body&.to_trix_html
15
+ end
16
+ end
17
+ # rubocop:enable Naming/PredicateName
18
+ end)
19
+ end
@@ -10,4 +10,5 @@ ActiveRecord::ConnectionAdapters::Column.class_eval do
10
10
  def array
11
11
  false
12
12
  end
13
+ alias_method :array?, :array
13
14
  end
@@ -5,3 +5,14 @@ ActiveRecord::Filter.module_eval do
5
5
  @filters ||= HashWithIndifferentAccess.new
6
6
  end
7
7
  end
8
+
9
+ if Rails::VERSION::MAJOR == 6
10
+ ActiveRecord::Relation::Filter.module_eval do
11
+ def build_arel(aliases = nil)
12
+ arel = super
13
+ my_alias_tracker = ActiveRecord::Associations::AliasTracker.create(connection, table.name, [])
14
+ build_filters(arel, my_alias_tracker)
15
+ arel
16
+ end
17
+ end
18
+ end
@@ -6,10 +6,6 @@ module Motor
6
6
  def path
7
7
  Rails.application.routes.url_helpers.rails_blob_path(self, only_path: true)
8
8
  end
9
-
10
- def url
11
- Rails.application.routes.url_helpers.url_for(self)
12
- end
13
9
  end
14
10
  end
15
11
  end
@@ -22,40 +22,6 @@ module Motor
22
22
 
23
23
  DEFAULT_SCOPE_TYPE = 'default'
24
24
 
25
- DEFAULT_ACTIONS = [
26
- {
27
- name: 'create',
28
- display_name: 'Create',
29
- action_type: 'default',
30
- preferences: {},
31
- visible: true
32
- },
33
- {
34
- name: 'edit',
35
- display_name: 'Edit',
36
- action_type: 'default',
37
- preferences: {},
38
- visible: true
39
- },
40
- {
41
- name: 'remove',
42
- display_name: 'Remove',
43
- action_type: 'default',
44
- preferences: {},
45
- visible: true
46
- }
47
- ].freeze
48
-
49
- DEFAULT_TABS = [
50
- {
51
- name: 'details',
52
- display_name: 'Details',
53
- tab_type: 'default',
54
- preferences: {},
55
- visible: true
56
- }
57
- ].freeze
58
-
59
25
  module_function
60
26
 
61
27
  def call(cache_keys = {}, current_ability = nil)
@@ -78,3 +44,4 @@ require_relative './build_schema/reorder_schema'
78
44
  require_relative './build_schema/merge_schema_configs'
79
45
  require_relative './build_schema/apply_permissions'
80
46
  require_relative './build_schema/utils'
47
+ require_relative './build_schema/defaults'
@@ -2,113 +2,123 @@
2
2
 
3
3
  module Motor
4
4
  module BuildSchema
5
- ACTIVE_STORAGE_ATTACHMENT_SCHEMA = {
6
- name: 'active_storage/attachment',
7
- slug: 'active_storage__attachments',
8
- class_name: 'ActiveStorage::Attachment',
9
- table_name: 'active_storage_attachments',
10
- primary_key: 'id',
11
- display_name: 'Attachments',
12
- display_column: 'filename',
13
- icon: 'paperclip',
14
- columns: [
15
- {
16
- name: 'id',
17
- display_name: 'ID',
18
- column_type: 'integer',
19
- access_type: 'read_only',
20
- default_value: nil,
21
- validators: [],
22
- format: {},
23
- is_array: false,
24
- reference: nil,
25
- virtual: false
26
- },
27
- {
28
- name: 'path',
29
- display_name: 'Path',
30
- column_type: 'string',
31
- access_type: 'read_only',
32
- default_value: nil,
33
- validators: [],
34
- format: {},
35
- is_array: false,
36
- reference: nil,
37
- virtual: true
38
- },
39
- {
40
- name: 'name',
41
- display_name: 'Name',
42
- column_type: 'string',
43
- access_type: 'read_write',
44
- default_value: nil,
45
- validators: [],
46
- format: {},
47
- is_array: false,
48
- reference: nil,
49
- virtual: false
50
- },
51
- {
52
- name: 'record_type',
53
- display_name: 'Record type',
54
- column_type: 'string',
55
- access_type: 'read_write',
56
- default_value: nil,
57
- validators: [],
58
- format: {},
59
- is_array: false,
60
- reference: nil,
61
- virtual: false
62
- },
63
- {
64
- name: 'record_id',
65
- display_name: 'Record',
66
- column_type: 'integer',
67
- access_type: 'read_write',
68
- default_value: nil,
69
- validators: [],
70
- format: {},
71
- is_array: false,
72
- reference: {
73
- name: 'record',
74
- display_name: 'Record',
75
- model_name: nil,
76
- reference_type: 'belongs_to',
77
- foreign_key: 'record_id',
78
- polymorphic: true
79
- },
80
- virtual: false
81
- },
82
- {
83
- name: 'file',
84
- display_name: 'File',
85
- column_type: 'file',
86
- access_type: 'write_only',
87
- default_value: nil,
88
- validators: [],
89
- format: {},
90
- is_array: false,
91
- reference: nil,
92
- virtual: false
93
- },
5
+ module ActiveStorageAttachmentSchema
6
+ module_function
7
+
8
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
9
+ def call
10
+ model = ActiveStorage::Attachment
11
+
94
12
  {
95
- name: 'created_at',
96
- display_name: 'Created at',
97
- column_type: 'datetime',
98
- access_type: 'read_only',
99
- default_value: nil,
100
- validators: [],
101
- format: {},
102
- is_array: false,
103
- reference: nil,
104
- virtual: false
105
- }
106
- ],
107
- associations: [],
108
- scopes: [],
109
- actions: Motor::BuildSchema::DEFAULT_ACTIONS.reject { |e| e[:name] == 'edit' },
110
- tabs: Motor::BuildSchema::DEFAULT_TABS,
111
- visible: true
112
- }.with_indifferent_access
13
+ name: model.name.underscore,
14
+ slug: Utils.slugify(model),
15
+ class_name: model.class.name,
16
+ table_name: model.table_name,
17
+ primary_key: model.primary_key,
18
+ display_name: model.model_name.human(count: 2, default: 'Attachments'),
19
+ display_column: 'filename',
20
+ icon: 'paperclip',
21
+ columns: [
22
+ {
23
+ name: 'id',
24
+ display_name: 'ID',
25
+ column_type: 'integer',
26
+ access_type: 'read_only',
27
+ default_value: nil,
28
+ validators: [],
29
+ format: {},
30
+ is_array: false,
31
+ reference: nil,
32
+ virtual: false
33
+ },
34
+ {
35
+ name: 'path',
36
+ display_name: model.human_attribute_name(:path),
37
+ column_type: 'string',
38
+ access_type: 'read_only',
39
+ default_value: nil,
40
+ validators: [],
41
+ format: {},
42
+ is_array: false,
43
+ reference: nil,
44
+ virtual: true
45
+ },
46
+ {
47
+ name: 'name',
48
+ display_name: model.human_attribute_name(:name),
49
+ column_type: 'string',
50
+ access_type: 'read_write',
51
+ default_value: nil,
52
+ validators: [],
53
+ format: {},
54
+ is_array: false,
55
+ reference: nil,
56
+ virtual: false
57
+ },
58
+ {
59
+ name: 'record_type',
60
+ display_name: model.human_attribute_name(:record_type),
61
+ column_type: 'string',
62
+ access_type: 'read_write',
63
+ default_value: nil,
64
+ validators: [],
65
+ format: {},
66
+ is_array: false,
67
+ reference: nil,
68
+ virtual: false
69
+ },
70
+ {
71
+ name: 'record_id',
72
+ display_name: model.human_attribute_name(:record),
73
+ column_type: 'integer',
74
+ access_type: 'read_write',
75
+ default_value: nil,
76
+ validators: [],
77
+ format: {},
78
+ is_array: false,
79
+ reference: {
80
+ name: 'record',
81
+ display_name: model.human_attribute_name(:record),
82
+ model_name: nil,
83
+ reference_type: 'belongs_to',
84
+ foreign_key: 'record_id',
85
+ polymorphic: true
86
+ },
87
+ virtual: false
88
+ },
89
+ {
90
+ name: 'file',
91
+ display_name: model.human_attribute_name(:file),
92
+ column_type: 'file',
93
+ access_type: 'write_only',
94
+ default_value: nil,
95
+ validators: [],
96
+ format: {},
97
+ is_array: false,
98
+ reference: nil,
99
+ virtual: false
100
+ },
101
+ {
102
+ name: 'created_at',
103
+ display_name: model.human_attribute_name(:created_at),
104
+ column_type: 'datetime',
105
+ access_type: 'read_only',
106
+ default_value: nil,
107
+ validators: [],
108
+ format: {},
109
+ is_array: false,
110
+ reference: nil,
111
+ virtual: false
112
+ }
113
+ ],
114
+ associations: [],
115
+ scopes: [],
116
+ actions: Motor::BuildSchema::Defaults.actions.reject { |e| e[:name] == 'edit' },
117
+ tabs: Motor::BuildSchema::Defaults.tabs,
118
+ visible: true
119
+ }.with_indifferent_access
120
+ end
121
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
122
+ end
113
123
  end
114
124
  end
@@ -47,7 +47,7 @@ module Motor
47
47
  def add_password_column!(columns)
48
48
  columns << {
49
49
  name: 'password',
50
- display_name: 'Password',
50
+ display_name: I18n.t('motor.password'),
51
51
  column_type: 'string',
52
52
  access_type: 'write_only',
53
53
  default_value: nil,
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module BuildSchema
5
+ module Defaults
6
+ module_function
7
+
8
+ # rubocop:disable Metrics/MethodLength
9
+ def actions
10
+ [
11
+ {
12
+ name: 'create',
13
+ display_name: I18n.t('motor.create'),
14
+ action_type: 'default',
15
+ preferences: {},
16
+ visible: true
17
+ },
18
+ {
19
+ name: 'edit',
20
+ display_name: I18n.t('motor.edit'),
21
+ action_type: 'default',
22
+ preferences: {},
23
+ visible: true
24
+ },
25
+ {
26
+ name: 'remove',
27
+ display_name: I18n.t('motor.remove'),
28
+ action_type: 'default',
29
+ preferences: {},
30
+ visible: true
31
+ }
32
+ ].freeze
33
+ end
34
+ # rubocop:enable Metrics/MethodLength
35
+
36
+ def tabs
37
+ [
38
+ {
39
+ name: 'details',
40
+ display_name: I18n.t('motor.details'),
41
+ tab_type: 'default',
42
+ preferences: {},
43
+ visible: true
44
+ }
45
+ ].freeze
46
+ end
47
+ end
48
+ end
49
+ end
@@ -6,6 +6,13 @@ module Motor
6
6
  MUTEX = Mutex.new
7
7
  UNIFIED_TYPES = ActiveRecordUtils::Types::UNIFIED_TYPES
8
8
 
9
+ I18N_SCOPES_KEY = 'activerecord.scopes'
10
+
11
+ ACTION_TEXT_REFLECTION_PREFIX = 'rich_text_'
12
+ ACTION_TEXT_COLUMN_SUFFIX = '_body'
13
+ ACTION_TEXT_SCOPE_PREFIX = 'with_rich_text_'
14
+ ACTIVE_STORAGE_SCOPE_PREFIX = 'with_attached_'
15
+
9
16
  module_function
10
17
 
11
18
  def call
@@ -38,6 +45,7 @@ module Motor
38
45
  models -= [ActiveRecord::SchemaMigration] if defined?(ActiveRecord::SchemaMigration)
39
46
  models -= [ActiveRecord::InternalMetadata] if defined?(ActiveRecord::InternalMetadata)
40
47
  models -= [ActiveStorage::Blob] if defined?(ActiveStorage::Blob)
48
+ models -= [ActionText::RichText] if defined?(ActionText::RichText)
41
49
  models -= [ActiveStorage::VariantRecord] if defined?(ActiveStorage::VariantRecord)
42
50
 
43
51
  models
@@ -46,7 +54,7 @@ module Motor
46
54
  def build_model_schema(model)
47
55
  model_name = model.name
48
56
 
49
- return Motor::BuildSchema::ACTIVE_STORAGE_ATTACHMENT_SCHEMA if model_name == 'ActiveStorage::Attachment'
57
+ return Motor::BuildSchema::ActiveStorageAttachmentSchema.call if model_name == 'ActiveStorage::Attachment'
50
58
 
51
59
  {
52
60
  name: model_name.underscore,
@@ -54,14 +62,14 @@ module Motor
54
62
  table_name: model.table_name,
55
63
  class_name: model.name,
56
64
  primary_key: model.primary_key,
57
- display_name: model_name.titleize.pluralize,
65
+ display_name: model.model_name.human(count: :many, default: model_name.titleize.pluralize),
58
66
  display_column: FindDisplayColumn.call(model),
59
67
  columns: fetch_columns(model),
60
68
  associations: fetch_associations(model),
61
- icon: Motor::FindIcon.call(model.name.titleize),
69
+ icon: Motor::FindIcon.call(model_name),
62
70
  scopes: fetch_scopes(model),
63
- actions: DEFAULT_ACTIONS,
64
- tabs: DEFAULT_TABS,
71
+ actions: BuildSchema::Defaults.actions,
72
+ tabs: BuildSchema::Defaults.tabs,
65
73
  visible: true
66
74
  }.with_indifferent_access
67
75
  end
@@ -70,11 +78,14 @@ module Motor
70
78
  model.defined_scopes.map do |scope_name|
71
79
  scope_name = scope_name.to_s
72
80
 
73
- next if scope_name.starts_with?('with_attached')
81
+ next if scope_name.starts_with?(ACTIVE_STORAGE_SCOPE_PREFIX)
82
+ next if scope_name.starts_with?(ACTION_TEXT_SCOPE_PREFIX)
74
83
 
75
84
  {
76
85
  name: scope_name,
77
- display_name: scope_name.humanize,
86
+ display_name: I18n.t(scope_name,
87
+ scope: [I18N_SCOPES_KEY, model.name.underscore].join('.'),
88
+ default: scope_name.humanize),
78
89
  scope_type: DEFAULT_SCOPE_TYPE,
79
90
  visible: true,
80
91
  preferences: {}
@@ -102,9 +113,9 @@ module Motor
102
113
 
103
114
  {
104
115
  name: column.name,
105
- display_name: Utils.humanize_column_name(column.name),
116
+ display_name: Utils.humanize_column_name(model.human_attribute_name(column.name)),
106
117
  column_type: is_enum ? 'string' : UNIFIED_TYPES[column.type.to_s] || column.type.to_s,
107
- is_array: column.respond_to?(:array?) && column.array?,
118
+ is_array: column.array?,
108
119
  access_type: COLUMN_NAME_ACCESS_TYPES.fetch(column.name, ColumnAccessTypes::READ_WRITE),
109
120
  default_value: default_attrs[column.name],
110
121
  validators: fetch_validators(model, column.name),
@@ -135,27 +146,47 @@ module Motor
135
146
  end
136
147
 
137
148
  def build_reflection_column(name, model, ref, default_attrs)
149
+ if !ref.polymorphic? && ref.klass.name == 'ActionText::RichText'
150
+ return build_action_text_column(name, model, ref)
151
+ end
152
+
138
153
  column_name = ref.belongs_to? ? ref.foreign_key.to_s : name
139
154
  is_attachment = !ref.polymorphic? && ref.klass.name == 'ActiveStorage::Attachment'
140
155
  access_type = ref.belongs_to? || is_attachment ? ColumnAccessTypes::READ_WRITE : ColumnAccessTypes::READ_ONLY
141
156
 
142
157
  {
143
158
  name: column_name,
144
- display_name: column_name.humanize,
159
+ display_name: model.human_attribute_name(name),
145
160
  column_type: is_attachment ? 'file' : 'integer',
146
161
  access_type: access_type,
147
162
  default_value: default_attrs[column_name],
148
163
  validators: fetch_validators(model, column_name, ref),
149
164
  format: {},
150
- reference: build_reference(name, ref),
165
+ reference: build_reference(model, name, ref),
151
166
  virtual: false
152
167
  }
153
168
  end
154
169
 
155
- def build_reference(name, reflection)
170
+ def build_action_text_column(name, model, ref)
171
+ name = name.delete_prefix(ACTION_TEXT_REFLECTION_PREFIX)
172
+
173
+ {
174
+ name: name + ACTION_TEXT_COLUMN_SUFFIX,
175
+ display_name: model.human_attribute_name(name),
176
+ column_type: 'richtext',
177
+ access_type: BuildSchema::ColumnAccessTypes::READ_WRITE,
178
+ default_value: '',
179
+ validators: fetch_validators(model, name, ref),
180
+ format: {},
181
+ reference: nil,
182
+ virtual: true
183
+ }
184
+ end
185
+
186
+ def build_reference(model, name, reflection)
156
187
  {
157
188
  name: name,
158
- display_name: name.humanize,
189
+ display_name: model.human_attribute_name(name),
159
190
  model_name: reflection.polymorphic? ? nil : reflection.klass.name.underscore,
160
191
  reference_type: reflection.belongs_to? ? 'belongs_to' : 'has_one',
161
192
  foreign_key: reflection.foreign_key,
@@ -175,7 +206,7 @@ module Motor
175
206
 
176
207
  {
177
208
  name: name,
178
- display_name: name.humanize,
209
+ display_name: model.human_attribute_name(name),
179
210
  slug: name.underscore,
180
211
  model_name: model_class.name.underscore,
181
212
  foreign_key: ref.foreign_key,