motor-admin-cstham8 0.4.35

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +661 -0
  3. data/README.md +230 -0
  4. data/Rakefile +11 -0
  5. data/app/channels/motor/application_cable/channel.rb +14 -0
  6. data/app/channels/motor/application_cable/connection.rb +27 -0
  7. data/app/channels/motor/notes_channel.rb +9 -0
  8. data/app/channels/motor/notifications_channel.rb +9 -0
  9. data/app/controllers/concerns/motor/current_ability.rb +21 -0
  10. data/app/controllers/concerns/motor/current_user_method.rb +18 -0
  11. data/app/controllers/concerns/motor/load_and_authorize_dynamic_resource.rb +73 -0
  12. data/app/controllers/concerns/motor/wrap_io_params.rb +25 -0
  13. data/app/controllers/motor/active_storage_attachments_controller.rb +64 -0
  14. data/app/controllers/motor/alerts_controller.rb +82 -0
  15. data/app/controllers/motor/api_base_controller.rb +33 -0
  16. data/app/controllers/motor/api_configs_controller.rb +54 -0
  17. data/app/controllers/motor/application_controller.rb +8 -0
  18. data/app/controllers/motor/assets_controller.rb +43 -0
  19. data/app/controllers/motor/audits_controller.rb +16 -0
  20. data/app/controllers/motor/auth_tokens_controller.rb +36 -0
  21. data/app/controllers/motor/configs_controller.rb +33 -0
  22. data/app/controllers/motor/dashboards_controller.rb +64 -0
  23. data/app/controllers/motor/data_controller.rb +88 -0
  24. data/app/controllers/motor/forms_controller.rb +61 -0
  25. data/app/controllers/motor/icons_controller.rb +22 -0
  26. data/app/controllers/motor/note_tags_controller.rb +13 -0
  27. data/app/controllers/motor/notes_controller.rb +58 -0
  28. data/app/controllers/motor/notifications_controller.rb +33 -0
  29. data/app/controllers/motor/queries_controller.rb +64 -0
  30. data/app/controllers/motor/reminders_controller.rb +38 -0
  31. data/app/controllers/motor/resource_default_queries_controller.rb +23 -0
  32. data/app/controllers/motor/resource_methods_controller.rb +23 -0
  33. data/app/controllers/motor/resources_controller.rb +26 -0
  34. data/app/controllers/motor/run_api_requests_controller.rb +56 -0
  35. data/app/controllers/motor/run_graphql_requests_controller.rb +48 -0
  36. data/app/controllers/motor/run_queries_controller.rb +77 -0
  37. data/app/controllers/motor/schema_controller.rb +31 -0
  38. data/app/controllers/motor/send_alerts_controller.rb +26 -0
  39. data/app/controllers/motor/sessions_controller.rb +23 -0
  40. data/app/controllers/motor/slack_conversations_controller.rb +11 -0
  41. data/app/controllers/motor/tags_controller.rb +11 -0
  42. data/app/controllers/motor/ui_controller.rb +51 -0
  43. data/app/controllers/motor/users_for_autocomplete_controller.rb +23 -0
  44. data/app/jobs/motor/alert_sending_job.rb +13 -0
  45. data/app/jobs/motor/application_job.rb +6 -0
  46. data/app/jobs/motor/notify_note_mentions_job.rb +9 -0
  47. data/app/jobs/motor/notify_reminder_job.rb +9 -0
  48. data/app/mailers/motor/alerts_mailer.rb +39 -0
  49. data/app/mailers/motor/application_mailer.rb +33 -0
  50. data/app/mailers/motor/notifications_mailer.rb +33 -0
  51. data/app/models/motor/alert.rb +30 -0
  52. data/app/models/motor/alert_lock.rb +7 -0
  53. data/app/models/motor/api_config.rb +28 -0
  54. data/app/models/motor/application_record.rb +18 -0
  55. data/app/models/motor/audit.rb +13 -0
  56. data/app/models/motor/config.rb +13 -0
  57. data/app/models/motor/dashboard.rb +26 -0
  58. data/app/models/motor/form.rb +23 -0
  59. data/app/models/motor/note.rb +18 -0
  60. data/app/models/motor/note_tag.rb +7 -0
  61. data/app/models/motor/note_tag_tag.rb +8 -0
  62. data/app/models/motor/notification.rb +14 -0
  63. data/app/models/motor/query.rb +33 -0
  64. data/app/models/motor/reminder.rb +13 -0
  65. data/app/models/motor/resource.rb +15 -0
  66. data/app/models/motor/tag.rb +7 -0
  67. data/app/models/motor/taggable_tag.rb +8 -0
  68. data/app/views/layouts/motor/application.html.erb +17 -0
  69. data/app/views/layouts/motor/mailer.html.erb +72 -0
  70. data/app/views/motor/alerts_mailer/alert_email.html.erb +54 -0
  71. data/app/views/motor/notifications_mailer/notify_mention_email.html.erb +28 -0
  72. data/app/views/motor/notifications_mailer/notify_reminder_email.html.erb +28 -0
  73. data/app/views/motor/ui/show.html.erb +1 -0
  74. data/config/locales/el.yml +420 -0
  75. data/config/locales/en.yml +340 -0
  76. data/config/locales/es.yml +420 -0
  77. data/config/locales/ja.yml +340 -0
  78. data/config/locales/pt.yml +416 -0
  79. data/config/routes.rb +65 -0
  80. data/lib/generators/motor/install_generator.rb +24 -0
  81. data/lib/generators/motor/install_notes_generator.rb +22 -0
  82. data/lib/generators/motor/migration.rb +17 -0
  83. data/lib/generators/motor/templates/install.rb +271 -0
  84. data/lib/generators/motor/templates/install_api_configs.rb +86 -0
  85. data/lib/generators/motor/templates/install_notes.rb +83 -0
  86. data/lib/generators/motor/templates/upgrade_motor_api_actions.rb +71 -0
  87. data/lib/generators/motor/upgrade_generator.rb +43 -0
  88. data/lib/motor/active_record_utils/action_text_attribute_patch.rb +19 -0
  89. data/lib/motor/active_record_utils/active_record_connection_column_patch.rb +14 -0
  90. data/lib/motor/active_record_utils/active_record_filter.rb +405 -0
  91. data/lib/motor/active_record_utils/active_storage_blob_patch.rb +30 -0
  92. data/lib/motor/active_record_utils/active_storage_links_extension.rb +11 -0
  93. data/lib/motor/active_record_utils/defined_scopes_extension.rb +25 -0
  94. data/lib/motor/active_record_utils/fetch_methods.rb +24 -0
  95. data/lib/motor/active_record_utils/types.rb +64 -0
  96. data/lib/motor/active_record_utils.rb +45 -0
  97. data/lib/motor/admin.rb +141 -0
  98. data/lib/motor/alerts/persistance.rb +97 -0
  99. data/lib/motor/alerts/scheduled_alerts_cache.rb +29 -0
  100. data/lib/motor/alerts/scheduler.rb +30 -0
  101. data/lib/motor/alerts/slack_sender.rb +74 -0
  102. data/lib/motor/alerts.rb +52 -0
  103. data/lib/motor/api_configs.rb +41 -0
  104. data/lib/motor/api_query/apply_scope.rb +44 -0
  105. data/lib/motor/api_query/build_json.rb +171 -0
  106. data/lib/motor/api_query/build_meta.rb +20 -0
  107. data/lib/motor/api_query/filter.rb +125 -0
  108. data/lib/motor/api_query/paginate.rb +19 -0
  109. data/lib/motor/api_query/search.rb +60 -0
  110. data/lib/motor/api_query/sort.rb +64 -0
  111. data/lib/motor/api_query.rb +24 -0
  112. data/lib/motor/assets.rb +62 -0
  113. data/lib/motor/build_schema/active_storage_attachment_schema.rb +125 -0
  114. data/lib/motor/build_schema/adjust_devise_model_schema.rb +60 -0
  115. data/lib/motor/build_schema/apply_permissions.rb +64 -0
  116. data/lib/motor/build_schema/defaults.rb +66 -0
  117. data/lib/motor/build_schema/find_display_column.rb +65 -0
  118. data/lib/motor/build_schema/find_icon.rb +135 -0
  119. data/lib/motor/build_schema/find_searchable_columns.rb +33 -0
  120. data/lib/motor/build_schema/load_from_rails.rb +361 -0
  121. data/lib/motor/build_schema/merge_schema_configs.rb +157 -0
  122. data/lib/motor/build_schema/reorder_schema.rb +88 -0
  123. data/lib/motor/build_schema/utils.rb +31 -0
  124. data/lib/motor/build_schema.rb +125 -0
  125. data/lib/motor/cancan_utils/ability_patch.rb +31 -0
  126. data/lib/motor/cancan_utils/can_manage_all.rb +14 -0
  127. data/lib/motor/cancan_utils.rb +9 -0
  128. data/lib/motor/configs/build_configs_hash.rb +90 -0
  129. data/lib/motor/configs/build_ui_app_tag.rb +177 -0
  130. data/lib/motor/configs/load_from_cache.rb +110 -0
  131. data/lib/motor/configs/sync_from_file.rb +35 -0
  132. data/lib/motor/configs/sync_from_hash.rb +159 -0
  133. data/lib/motor/configs/sync_middleware.rb +72 -0
  134. data/lib/motor/configs/sync_with_remote.rb +47 -0
  135. data/lib/motor/configs/write_to_file.rb +36 -0
  136. data/lib/motor/configs.rb +39 -0
  137. data/lib/motor/dashboards/persistance.rb +73 -0
  138. data/lib/motor/dashboards.rb +8 -0
  139. data/lib/motor/forms/persistance.rb +93 -0
  140. data/lib/motor/forms.rb +8 -0
  141. data/lib/motor/hash_serializer.rb +21 -0
  142. data/lib/motor/net_http_utils.rb +50 -0
  143. data/lib/motor/notes/notify_mentions.rb +71 -0
  144. data/lib/motor/notes/notify_reminder.rb +48 -0
  145. data/lib/motor/notes/persist.rb +36 -0
  146. data/lib/motor/notes/reminders_scheduler.rb +39 -0
  147. data/lib/motor/notes/tags.rb +34 -0
  148. data/lib/motor/notes.rb +12 -0
  149. data/lib/motor/queries/persistance.rb +90 -0
  150. data/lib/motor/queries/postgresql_exec_query.rb +28 -0
  151. data/lib/motor/queries/render_sql_template.rb +61 -0
  152. data/lib/motor/queries/run_query.rb +289 -0
  153. data/lib/motor/queries.rb +11 -0
  154. data/lib/motor/railtie.rb +11 -0
  155. data/lib/motor/resources/custom_sql_columns_cache.rb +17 -0
  156. data/lib/motor/resources/fetch_configured_model.rb +269 -0
  157. data/lib/motor/resources/persist_configs.rb +232 -0
  158. data/lib/motor/resources.rb +19 -0
  159. data/lib/motor/slack/client.rb +62 -0
  160. data/lib/motor/slack.rb +16 -0
  161. data/lib/motor/tags.rb +32 -0
  162. data/lib/motor/tasks/motor.rake +54 -0
  163. data/lib/motor/version.rb +5 -0
  164. data/lib/motor-admin-cstham8.rb +3 -0
  165. data/lib/motor.rb +87 -0
  166. data/ui/dist/manifest.json +1990 -0
  167. metadata +303 -0
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module BuildSchema
5
+ module MergeSchemaConfigs
6
+ module_function
7
+
8
+ # @param schema [Array<HashWithIndifferentAccess>]
9
+ # @param cache_keys [Hash]
10
+ # @return [Array<HashWithIndifferentAccess>]
11
+ def call(schema, cache_keys = {})
12
+ configs = load_configs(cache_keys)
13
+
14
+ schema.map do |model|
15
+ merge_model(model, configs.fetch(model[:name], {}))
16
+ end
17
+ end
18
+
19
+ # @param model [HashWithIndifferentAccess]
20
+ # @param configs [HashWithIndifferentAccess]
21
+ # @return [HashWithIndifferentAccess]
22
+ def merge_model(model, configs)
23
+ updated_model = model.merge(configs.slice(*Resources::RESOURCE_ATTRS))
24
+
25
+ merge_actions!(updated_model, configs)
26
+ merge_associations!(updated_model, configs)
27
+ merge_columns!(updated_model, configs)
28
+ merge_tabs!(updated_model, configs)
29
+ merge_scopes!(updated_model, configs)
30
+
31
+ updated_model
32
+ end
33
+
34
+ # @param model [HashWithIndifferentAccess]
35
+ # @param configs [HashWithIndifferentAccess]
36
+ # @return [HashWithIndifferentAccess]
37
+ def merge_associations!(model, configs)
38
+ model[:associations] = merge_by_name(
39
+ model[:associations],
40
+ configs[:associations],
41
+ ASSOCIATION_DEFAULTS,
42
+ ->(scope) { !scope[:virtual] }
43
+ )
44
+
45
+ model
46
+ end
47
+
48
+ # @param model [HashWithIndifferentAccess]
49
+ # @param configs [HashWithIndifferentAccess]
50
+ # @return [HashWithIndifferentAccess]
51
+ def merge_columns!(model, configs)
52
+ model[:columns] = merge_by_name(
53
+ merge_custom_sql_columns(model[:columns], configs[:custom_sql]),
54
+ configs[:columns],
55
+ COLUMN_DEFAULTS,
56
+ ->(scope) { !scope[:virtual] }
57
+ )
58
+
59
+ model
60
+ end
61
+
62
+ # @param model [HashWithIndifferentAccess]
63
+ # @param configs [HashWithIndifferentAccess]
64
+ # @return [HashWithIndifferentAccess]
65
+ def merge_actions!(model, configs)
66
+ model[:actions] = merge_by_name(
67
+ model[:actions],
68
+ configs[:actions],
69
+ ACTION_DEFAULTS
70
+ )
71
+
72
+ model
73
+ end
74
+
75
+ # @param model [HashWithIndifferentAccess]
76
+ # @param configs [HashWithIndifferentAccess]
77
+ # @return [HashWithIndifferentAccess]
78
+ def merge_tabs!(model, configs)
79
+ model[:tabs] = merge_by_name(
80
+ model[:tabs],
81
+ configs[:tabs],
82
+ TAB_DEFAULTS
83
+ )
84
+
85
+ model
86
+ end
87
+
88
+ # @param model [HashWithIndifferentAccess]
89
+ # @param configs [HashWithIndifferentAccess]
90
+ # @return [HashWithIndifferentAccess]
91
+ def merge_scopes!(model, configs)
92
+ model[:scopes] = merge_by_name(
93
+ model[:scopes],
94
+ configs[:scopes],
95
+ SCOPE_DEFAULTS,
96
+ ->(scope) { scope[:scope_type] != 'filter' }
97
+ )
98
+
99
+ model
100
+ end
101
+
102
+ # @param defaults [Array<HashWithIndifferentAccess>]
103
+ # @param configs [Array<HashWithIndifferentAccess>]
104
+ # @return [Array<HashWithIndifferentAccess>]
105
+ def merge_by_name(defaults, configs, default_attrs = {}, default_item_check = nil)
106
+ return defaults if configs.blank?
107
+
108
+ (defaults.pluck(:name) + configs.pluck(:name)).uniq.map do |name|
109
+ config_item = configs.find { |e| e[:name] == name }
110
+ default_item = defaults.find { |e| e[:name] == name }
111
+
112
+ next if default_item.nil? && default_item_check&.call(config_item)
113
+
114
+ (default_item || default_attrs).merge(config_item || {})
115
+ end.compact
116
+ end
117
+
118
+ # @param columns [Array<HashWithIndifferentAccess>]
119
+ # @param sql [String]
120
+ # @return [Array<HashWithIndifferentAccess>]
121
+ def merge_custom_sql_columns(columns, sql)
122
+ return columns if sql.blank?
123
+
124
+ query_columns = Resources::CustomSqlColumnsCache.call(sql)
125
+
126
+ columns_index = columns.index_by { |e| e[:name] }
127
+
128
+ merged_columns =
129
+ query_columns.map do |column|
130
+ existing_column = columns_index.delete(column[:name])
131
+
132
+ next existing_column if existing_column
133
+
134
+ column.merge(COLUMN_DEFAULTS).merge(
135
+ access_type: ColumnAccessTypes::READ_ONLY,
136
+ column_source: ColumnSources::QUERY,
137
+ virtual: false
138
+ ).with_indifferent_access
139
+ end
140
+
141
+ reflection_columns = columns_index.values.select { |c| c[:column_source] == ColumnSources::REFLECTION }
142
+
143
+ reflection_columns + merged_columns
144
+ end
145
+
146
+ # @param cache_keys [Hash]
147
+ # @return [HashWithIndifferentAccess<String, HashWithIndifferentAccess>]
148
+ def load_configs(cache_keys)
149
+ resources = Motor::Configs::LoadFromCache.load_resources(cache_key: cache_keys[:resources])
150
+
151
+ resources.each_with_object(ActiveSupport::HashWithIndifferentAccess.new) do |resource, acc|
152
+ acc[resource.name] = resource.preferences
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module ReorderSchema
5
+ COLUMNS_DEFAULT_ORDER_WEIGHTS = {
6
+ id: 0,
7
+ updated_at: 2,
8
+ edited_at: 2,
9
+ created_at: 3,
10
+ inserted_at: 3,
11
+ deleted_at: 4,
12
+ archived_at: 4
13
+ }.with_indifferent_access
14
+
15
+ COLUMNS_DEFAULT_ORDER_WEIGHT = 1
16
+
17
+ module_function
18
+
19
+ # @param cache_keys [Hash]
20
+ # @param schema [Array<HashWithIndifferentAccess>]
21
+ # @return [Array<HashWithIndifferentAccess>]
22
+ def call(schema, cache_keys = {})
23
+ configs = load_configs(cache_keys)
24
+
25
+ schema = sort_by_name(schema, configs['resources.order'])
26
+
27
+ schema.map { |model| reorder_model(model, configs) }
28
+ end
29
+
30
+ def reorder_model(model, configs)
31
+ order_configs = build_order_configs(model[:name], configs)
32
+
33
+ model.merge(
34
+ columns: sort_by_name(sort_columns(model[:columns]), order_configs[:columns], sort_alphabetically: false),
35
+ associations: sort_by_name(model[:associations], order_configs[:associations]),
36
+ actions: sort_by_name(model[:actions], order_configs[:actions], sort_alphabetically: false),
37
+ tabs: sort_by_name(model[:tabs], order_configs[:tabs], sort_alphabetically: false),
38
+ scopes: sort_by_name(model[:scopes], order_configs[:scopes])
39
+ )
40
+ end
41
+
42
+ def build_order_configs(model_name, configs)
43
+ {
44
+ columns: configs["resources.#{model_name}.columns.order"],
45
+ associations: configs["resources.#{model_name}.associations.order"],
46
+ actions: configs["resources.#{model_name}.actions.order"],
47
+ tabs: configs["resources.#{model_name}.tabs.order"],
48
+ scopes: configs["resources.#{model_name}.scopes.order"]
49
+ }
50
+ end
51
+
52
+ # @param list [Array<HashWithIndifferentAccess>]
53
+ # @param sort_alphabetically [Boolean]
54
+ # @param order [Array<String>]
55
+ # @return [Array<HashWithIndifferentAccess>]
56
+ def sort_by_name(list, order, sort_alphabetically: true)
57
+ return list if order.blank? && !sort_alphabetically
58
+
59
+ list.sort_by do |item|
60
+ if order.present?
61
+ order.index(item[:name]) || Float::MAX
62
+ else
63
+ item[:display_name].to_s
64
+ end
65
+ end
66
+ end
67
+
68
+ # @param columns [Array<HashWithIndifferentAccess>]
69
+ # @return [Array<HashWithIndifferentAccess>]
70
+ def sort_columns(columns)
71
+ columns.each_with_object([]) do |column, acc|
72
+ weight = COLUMNS_DEFAULT_ORDER_WEIGHTS.fetch(column[:name], COLUMNS_DEFAULT_ORDER_WEIGHT)
73
+
74
+ (acc[weight] ||= []) << column
75
+ end.flatten.compact
76
+ end
77
+
78
+ # @param cache_keys [Hash]
79
+ # @return [Hash<String, HashWithIndifferentAccess>]
80
+ def load_configs(cache_keys = {})
81
+ configs = Motor::Configs::LoadFromCache.load_configs(cache_key: cache_keys[:configs])
82
+
83
+ configs.each_with_object({}) do |config, acc|
84
+ acc[config.key] = config.value
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module BuildSchema
5
+ module Utils
6
+ ABBREVIATIONS = {
7
+ 'Id' => 'ID',
8
+ 'Uuid' => 'UUID',
9
+ 'Url' => 'URL',
10
+ 'Iso' => 'ISO',
11
+ 'vip' => 'VIP',
12
+ 'Ip' => 'IP',
13
+ 'Zip' => 'ZIP'
14
+ }.freeze
15
+
16
+ module_function
17
+
18
+ def slugify(model)
19
+ model.name.underscore.pluralize.gsub('/', '__')
20
+ end
21
+
22
+ def classify_slug(slug)
23
+ slug.singularize.gsub('__', '/').classify.constantize
24
+ end
25
+
26
+ def humanize_column_name(column_name)
27
+ ABBREVIATIONS.fetch(column_name, column_name.humanize)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module BuildSchema
5
+ module ColumnAccessTypes
6
+ ALL = [
7
+ READ_ONLY = 'read_only',
8
+ WRITE_ONLY = 'write_only',
9
+ READ_WRITE = 'read_write',
10
+ HIDDEN = 'hidden'
11
+ ].freeze
12
+ end
13
+
14
+ module ColumnTypes
15
+ ALL = [
16
+ STRING = 'string',
17
+ INTEGER = 'integer',
18
+ FLOAT = 'float',
19
+ REFERENCE = 'reference',
20
+ DATETIME = 'datetime',
21
+ DATE = 'date',
22
+ BOOLEAN = 'boolean',
23
+ TEXTAREA = 'textarea',
24
+ RICHTEXT = 'richtext',
25
+ CURRENCY = 'currency',
26
+ PERCENTAGE = 'percentage',
27
+ CHANGE = 'change',
28
+ CHART = 'chart',
29
+ TAG = 'tag',
30
+ LINK = 'link',
31
+ COLOR = 'color',
32
+ IMAGE = 'image',
33
+ FILE = 'file',
34
+ JSON = 'json'
35
+ ].freeze
36
+ end
37
+
38
+ module ColumnSources
39
+ ALL = [
40
+ TABLE = 'table',
41
+ QUERY = 'query',
42
+ REFLECTION = 'reflection'
43
+ ].freeze
44
+ end
45
+
46
+ SEARCHABLE_COLUMN_TYPES = %i[citext text string bitstring].freeze
47
+
48
+ DEFAULT_TYPE = 'default'
49
+ DEFAULT_ICON = 'database'
50
+
51
+ COLUMN_NAME_ACCESS_TYPES = {
52
+ id: ColumnAccessTypes::READ_ONLY,
53
+ created_at: ColumnAccessTypes::READ_ONLY,
54
+ created_on: ColumnAccessTypes::READ_ONLY,
55
+ inserted_at: ColumnAccessTypes::READ_ONLY,
56
+ updated_at: ColumnAccessTypes::READ_ONLY,
57
+ updated_on: ColumnAccessTypes::READ_ONLY,
58
+ modified_at: ColumnAccessTypes::READ_ONLY,
59
+ deleted_at: ColumnAccessTypes::READ_ONLY
60
+ }.with_indifferent_access.freeze
61
+
62
+ COLUMN_DEFAULTS = {
63
+ access_type: ColumnAccessTypes::READ_WRITE,
64
+ column_source: ColumnSources::TABLE,
65
+ default_value: nil,
66
+ reference: nil,
67
+ format: {},
68
+ validators: [],
69
+ description: ''
70
+ }.with_indifferent_access
71
+
72
+ ACTION_DEFAULTS = {
73
+ visible: true,
74
+ apply_on: 'member',
75
+ preferences: {}
76
+ }.with_indifferent_access
77
+
78
+ TAB_DEFAULTS = {
79
+ visible: true,
80
+ tab_type: DEFAULT_TYPE,
81
+ preferences: {}
82
+ }.with_indifferent_access
83
+
84
+ SCOPE_DEFAULTS = {
85
+ visible: true,
86
+ scope_type: DEFAULT_TYPE,
87
+ preferences: {}
88
+ }.with_indifferent_access
89
+
90
+ ASSOCIATION_DEFAULTS = {
91
+ visible: true,
92
+ icon: DEFAULT_ICON,
93
+ options: {}
94
+ }.with_indifferent_access
95
+
96
+ module_function
97
+
98
+ def call(cache_keys = {}, current_ability = nil)
99
+ schema = LoadFromRails.call
100
+ schema = MergeSchemaConfigs.call(schema, cache_keys)
101
+ schema = ApplyPermissions.call(schema, current_ability) if current_ability
102
+
103
+ ReorderSchema.call(schema, cache_keys)
104
+ end
105
+
106
+ def for_model(model)
107
+ schema = Motor::BuildSchema::LoadFromRails.build_model_schema(model)
108
+ configs = Motor::Resource.find_by(name: schema[:name]).preferences
109
+
110
+ MergeSchemaConfigs.merge_model(schema, configs)
111
+ end
112
+ end
113
+ end
114
+
115
+ require_relative 'build_schema/active_storage_attachment_schema'
116
+ require_relative 'build_schema/adjust_devise_model_schema'
117
+ require_relative 'build_schema/load_from_rails'
118
+ require_relative 'build_schema/find_display_column'
119
+ require_relative 'build_schema/find_icon'
120
+ require_relative 'build_schema/reorder_schema'
121
+ require_relative 'build_schema/merge_schema_configs'
122
+ require_relative 'build_schema/apply_permissions'
123
+ require_relative 'build_schema/utils'
124
+ require_relative 'build_schema/defaults'
125
+ require_relative 'build_schema/find_searchable_columns'
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module CancanUtils
5
+ module AbilityPatch
6
+ def serialized_rules
7
+ return [] unless @rules
8
+
9
+ @rules.map do |rule|
10
+ {
11
+ base_behavior: rule.base_behavior,
12
+ actions: expand_actions(rule.actions),
13
+ subjects: rule.subjects.map(&:to_s),
14
+ attributes: rule.attributes,
15
+ conditions: rule.conditions.as_json
16
+ }
17
+ end
18
+ end
19
+
20
+ def rules_hash
21
+ serialized_rules.hash
22
+ end
23
+
24
+ private
25
+
26
+ def default_alias_actions
27
+ super.merge(destroy: %i[remove delete])
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module CancanUtils
5
+ class CanManageAll
6
+ include CanCan::Ability
7
+ prepend CancanUtils::AbilityPatch
8
+
9
+ def initialize(_ = nil)
10
+ can :manage, :all
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module CancanUtils
5
+ end
6
+ end
7
+
8
+ require_relative 'cancan_utils/ability_patch'
9
+ require_relative 'cancan_utils/can_manage_all'
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Motor
4
+ module Configs
5
+ module BuildConfigsHash
6
+ module_function
7
+
8
+ def call
9
+ cache_keys = LoadFromCache.load_cache_keys
10
+
11
+ normalize_hash(
12
+ engine_version: Motor::VERSION,
13
+ file_version: cache_keys.values.compact.max.to_time,
14
+ resources: build_resources_hash(cache_keys[:resources]),
15
+ configs: build_configs_hash(cache_keys[:configs]),
16
+ queries: build_queries_hash(cache_keys[:queries]),
17
+ dashboards: build_dashboards_hash(cache_keys[:dashboards]),
18
+ forms: build_forms_hash(cache_keys[:forms]),
19
+ alerts: build_alerts_hash(cache_keys[:alerts]),
20
+ api_configs: build_api_configs_hash(cache_keys[:api_configs])
21
+ )
22
+ end
23
+
24
+ def build_queries_hash(cache_key = nil)
25
+ Motor::Configs::LoadFromCache.load_queries(cache_key: cache_key).sort_by(&:id).map do |query|
26
+ query.slice(%i[id name sql_body description preferences])
27
+ .merge(tags: query.tags.map(&:name), updated_at: query.updated_at.to_time)
28
+ end
29
+ end
30
+
31
+ def build_dashboards_hash(cache_key = nil)
32
+ Motor::Configs::LoadFromCache.load_dashboards(cache_key: cache_key).sort_by(&:id).map do |dashboard|
33
+ dashboard.slice(%i[id title description preferences])
34
+ .merge(tags: dashboard.tags.map(&:name), updated_at: dashboard.updated_at.to_time)
35
+ end
36
+ end
37
+
38
+ def build_alerts_hash(cache_key = nil)
39
+ Motor::Configs::LoadFromCache.load_alerts(cache_key: cache_key).sort_by(&:id).map do |alert|
40
+ alert.slice(%i[id name query_id to_emails is_enabled description preferences])
41
+ .merge(tags: alert.tags.map(&:name), updated_at: alert.updated_at.to_time)
42
+ end
43
+ end
44
+
45
+ def build_forms_hash(cache_key = nil)
46
+ Motor::Configs::LoadFromCache.load_forms(cache_key: cache_key).sort_by(&:id).map do |form|
47
+ form.slice(%i[id name http_method api_path description preferences api_config_name])
48
+ .merge(tags: form.tags.map(&:name), updated_at: form.updated_at.to_time)
49
+ end
50
+ end
51
+
52
+ def build_api_configs_hash(cache_key = nil)
53
+ Motor::Configs::LoadFromCache.load_api_configs(cache_key: cache_key).sort_by(&:id).map do |config|
54
+ config.slice(%i[id name url preferences description]).merge(updated_at: config.updated_at.to_time)
55
+ end
56
+ end
57
+
58
+ def build_configs_hash(cache_key = nil)
59
+ Motor::Configs::LoadFromCache.load_configs(cache_key: cache_key).sort_by(&:key).map do |config|
60
+ {
61
+ key: config.key,
62
+ value: config.value,
63
+ updated_at: config.updated_at.to_time
64
+ }
65
+ end
66
+ end
67
+
68
+ def build_resources_hash(cache_key = nil)
69
+ Motor::Configs::LoadFromCache.load_resources(cache_key: cache_key).sort_by(&:name).map do |resource|
70
+ {
71
+ name: resource.name,
72
+ preferences: resource.preferences,
73
+ updated_at: resource.updated_at.to_time
74
+ }
75
+ end
76
+ end
77
+
78
+ def normalize_hash(value)
79
+ case value
80
+ when Hash, ActiveSupport::HashWithIndifferentAccess
81
+ value.to_h.stringify_keys.transform_values { |v| normalize_hash(v) }
82
+ when Array
83
+ value.map { |e| normalize_hash(e) }
84
+ else
85
+ value
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end