motor-admin 0.1.47 → 0.1.52
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 +4 -4
- data/LICENSE +1 -1
- data/README.md +19 -13
- data/app/controllers/concerns/motor/current_user_method.rb +15 -0
- data/app/controllers/motor/api_base_controller.rb +13 -17
- data/app/controllers/motor/application_controller.rb +1 -0
- data/app/controllers/motor/assets_controller.rb +1 -1
- data/app/controllers/motor/ui_controller.rb +12 -4
- data/app/mailers/motor/alerts_mailer.rb +3 -3
- data/app/models/motor/alert.rb +1 -0
- data/app/models/motor/dashboard.rb +1 -0
- data/app/models/motor/form.rb +1 -0
- data/app/models/motor/query.rb +1 -0
- data/app/models/motor/resource.rb +1 -0
- data/app/models/motor/tag.rb +1 -1
- data/app/views/motor/ui/show.html.erb +1 -1
- data/config/routes.rb +8 -9
- data/lib/generators/motor/templates/install.rb +74 -65
- data/lib/motor.rb +0 -1
- data/lib/motor/active_record_utils.rb +13 -1
- data/lib/motor/active_record_utils/active_storage_blob_patch.rb +4 -0
- data/lib/motor/admin.rb +6 -7
- data/lib/motor/alerts/persistance.rb +4 -4
- data/lib/motor/alerts/scheduler.rb +1 -1
- data/lib/motor/api_query/apply_scope.rb +1 -1
- data/lib/motor/api_query/build_json.rb +6 -6
- data/lib/motor/api_query/paginate.rb +1 -0
- data/lib/motor/api_query/search.rb +1 -7
- data/lib/motor/api_query/sort.rb +3 -1
- data/lib/motor/assets.rb +1 -1
- data/lib/motor/build_schema/find_icon.rb +1 -0
- data/lib/motor/build_schema/load_from_rails.rb +5 -2
- data/lib/motor/configs/build_ui_app_tag.rb +6 -6
- data/lib/motor/configs/load_from_cache.rb +28 -16
- data/lib/motor/configs/sync_from_hash.rb +1 -1
- data/lib/motor/configs/sync_with_remote.rb +1 -1
- data/lib/motor/configs/write_to_file.rb +1 -0
- data/lib/motor/dashboards/persistance.rb +4 -4
- data/lib/motor/forms/persistance.rb +4 -4
- data/lib/motor/queries/persistance.rb +4 -4
- data/lib/motor/queries/run_query.rb +3 -3
- data/lib/motor/tags.rb +2 -2
- data/lib/motor/tasks/motor.rake +4 -0
- data/lib/motor/version.rb +1 -1
- data/ui/dist/{main-5cac10cadc5aa16e9b69.css.gz → main-36a9ee6a9b0427a77d87.css.gz} +0 -0
- data/ui/dist/main-36a9ee6a9b0427a77d87.js.gz +0 -0
- data/ui/dist/manifest.json +5 -5
- metadata +5 -4
- data/ui/dist/main-5cac10cadc5aa16e9b69.js.gz +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8798474d7c7dc20d6410dd00f13950997be5e3f5d67e1d2585a57af92cd8db10
|
4
|
+
data.tar.gz: 90fcc0b1835fe56b78ecfcc28de03f9d4397b213f6e499afc626c3f4d13b1ef9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3a34e36e74e5004508e420ba4cdf95e2784d52647dfefccb64fc078b2785cbdd42a7aad84ca41f4c86e2c680b76516f219a41739b7d19601798dda4c9319e06
|
7
|
+
data.tar.gz: 727c31fafba431b69e3206d0fb2cff568171760cd43b36b9a42e97a356d5e344c7cacb069c5e9e79899e0fa804f39fd122ae14e30aece4cb77ca64de31620c5f
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
Low-code Admin panel and Business intelligence Rails engine **(no DSL - configurable from the UI)**.
|
4
4
|
|
5
|
-
🤓 [Demo App](https://motor-admin
|
5
|
+
🤓 [Demo App](https://motor-admin.herokuapp.com/demo) | [Features overview](https://www.youtube.com/watch?v=ngVoci8Hll4&list=PLu7llEMh0KcOkR3Uy_RJT0cXPZQKAYVsq&index=1)
|
6
6
|
|
7
|
-
[](https://motor-admin.herokuapp.com/demo)
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
Add this line to your application's Gemfile:
|
@@ -20,7 +20,7 @@ $ bundle install
|
|
20
20
|
|
21
21
|
Create and run migration:
|
22
22
|
```bash
|
23
|
-
$ rails
|
23
|
+
$ rails motor:install && rake db:migrate
|
24
24
|
```
|
25
25
|
|
26
26
|
## Features
|
@@ -38,11 +38,11 @@ $ rails generate motor:install && rake db:migrate
|
|
38
38
|
|
39
39
|
### Customizable CRUD
|
40
40
|
|
41
|
-

|
42
42
|
|
43
43
|

|
44
44
|
|
45
|
-
Everything in the admin panel can be configured using
|
45
|
+
Everything in the admin panel can be configured using intuitive settings UI, which can be opened via the icon in the top right corner.
|
46
46
|
|
47
47
|
Data displayed on the resource page can be completely custimized via [SQL queries](#sql-queries) and [dashboards](#dashboards) attached to the resource as a tab. Usually, queries used to display resource data should contain `{{resource_name_id}}` [variable](#sql-queries).
|
48
48
|
|
@@ -50,13 +50,13 @@ Data displayed on the resource page can be completely custimized via [SQL querie
|
|
50
50
|
|
51
51
|

|
52
52
|
|
53
|
-
Custom resource actions can be added via Active Record method call, API endpoint, or [custom forms](#forms-builder). Also, it's possible to override default
|
53
|
+
Custom resource actions can be added via Active Record method call, API endpoint, or [custom forms](#forms-builder). Also, it's possible to override default create/update/delete actions.
|
54
54
|
|
55
55
|
### Forms Builder
|
56
56
|
|
57
57
|

|
58
58
|
|
59
|
-
Values from the form fields can be used in API path via `{field_name}` syntax: `/api/some-endpoint/{
|
59
|
+
Values from the form fields can be used in API path via `{field_name}` syntax: `/api/some-endpoint/{resource_id}/apply`
|
60
60
|
|
61
61
|
### SQL Queries
|
62
62
|
|
@@ -68,7 +68,7 @@ Queries can include embeded variables via `{{variable}}` syntax ([mustache](http
|
|
68
68
|
|
69
69
|

|
70
70
|
|
71
|
-
Data from the SQL query can be represented as: [table](https://motor-admin
|
71
|
+
Data from the SQL query can be represented as: [table](https://motor-admin.herokuapp.com/demo/queries/12), [number](https://motor-admin.herokuapp.com/demo/queries/6), [line chart](https://motor-admin.herokuapp.com/demo/queries/3), [bar chart](https://motor-admin.herokuapp.com/demo/queries/1), [pie chart](https://motor-admin.herokuapp.com/demo/queries/9), [funnel](https://motor-admin.herokuapp.com/demo/queries/7), [markdown](https://motor-admin.herokuapp.com/demo/queries/8)
|
72
72
|
|
73
73
|
### Dashboards
|
74
74
|
|
@@ -80,20 +80,20 @@ SQL queries can be organized into dashboards to create a convenient representati
|
|
80
80
|
|
81
81
|

|
82
82
|
|
83
|
-
Query data can be sent via email periodically using the alerts feature. Interval of the alert email can be specified using natural language, e.g
|
83
|
+
Query data can be sent via email periodically using the alerts feature. Interval of the alert email can be specified using natural language, e.g., `every day at midnight`, `every Monday at 8 PM`, `every weekday at 6AM and 6PM`, `every minute`.
|
84
84
|
|
85
|
-
|
85
|
+
Sender address can be specified using `MOTOR_ALERTS_FROM_ADDRESS` environment variable.
|
86
86
|
|
87
87
|
### Intelligence Search
|
88
88
|
|
89
89
|

|
90
90
|
|
91
|
-
Intelligence search can be opened
|
91
|
+
Intelligence search can be opened via the top right corner button or using <kbd>Cmd</kbd> + <kbd>P</kbd> shortcut.
|
92
92
|
|
93
93
|
|
94
94
|
### Optimized for Mobile
|
95
95
|
|
96
|
-

|
97
97
|
|
98
98
|
|
99
99
|
### Configurations Sync
|
@@ -127,6 +127,12 @@ Start webpack dev server:
|
|
127
127
|
yarn install && yarn serve
|
128
128
|
```
|
129
129
|
|
130
|
+
Setup development database:
|
131
|
+
|
132
|
+
```bash
|
133
|
+
rake app:db:create && rake app:db:setup
|
134
|
+
```
|
135
|
+
|
130
136
|
Start example application in development mode:
|
131
137
|
|
132
138
|
```bash
|
@@ -143,4 +149,4 @@ MOTOR_DEVELOPMENT=true rails s
|
|
143
149
|
|
144
150
|
## License
|
145
151
|
|
146
|
-
The gem is available as open source under the terms of the [MIT License](https://
|
152
|
+
The gem is available as open source under the terms of the [MIT License](https://github.com/omohokcoj/motor-admin/blob/master/LICENSE).
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module CurrentUserMethod
|
5
|
+
def current_user
|
6
|
+
if defined?(current_admin)
|
7
|
+
current_admin
|
8
|
+
elsif defined?(current_admin_user)
|
9
|
+
current_admin_user
|
10
|
+
elsif defined?(super)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -2,30 +2,26 @@
|
|
2
2
|
|
3
3
|
module Motor
|
4
4
|
class ApiBaseController < ActionController::API
|
5
|
-
|
6
|
-
Rails.logger.error(e)
|
5
|
+
include Motor::CurrentUserMethod
|
7
6
|
|
8
|
-
|
9
|
-
|
7
|
+
class CanCanAbilityManageAll
|
8
|
+
include CanCan::Ability
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
current_admin
|
14
|
-
elsif defined?(current_admin_user)
|
15
|
-
current_admin_user
|
16
|
-
elsif defined?(super)
|
17
|
-
super
|
10
|
+
def initialize(_)
|
11
|
+
can :manage, :all
|
18
12
|
end
|
19
13
|
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
15
|
+
unless Rails.env.test?
|
16
|
+
rescue_from StandardError do |e|
|
17
|
+
Rails.logger.error(e)
|
18
|
+
|
19
|
+
render json: { errors: [e.message] }, status: :internal_server_error
|
26
20
|
end
|
21
|
+
end
|
27
22
|
|
28
|
-
|
23
|
+
def current_ability
|
24
|
+
CanCanAbilityManageAll.new(current_user)
|
29
25
|
end
|
30
26
|
end
|
31
27
|
end
|
@@ -4,15 +4,23 @@ module Motor
|
|
4
4
|
class UiController < ApplicationController
|
5
5
|
layout 'motor/application'
|
6
6
|
|
7
|
-
|
8
|
-
Motor.reload! if Motor.development?
|
7
|
+
helper_method :current_user
|
9
8
|
|
10
|
-
|
9
|
+
def index
|
10
|
+
render_ui
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
+
def new
|
14
|
+
render_ui
|
13
15
|
end
|
14
16
|
|
15
17
|
def show
|
18
|
+
render_ui
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def render_ui
|
16
24
|
Motor.reload! if Motor.development?
|
17
25
|
|
18
26
|
Motor::Configs::SyncFromFile.call
|
@@ -26,11 +26,11 @@ module Motor
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def from_address
|
29
|
-
from = ENV['
|
29
|
+
from = ENV['MOTOR_ALERTS_FROM_ADDRESS'].presence
|
30
30
|
|
31
31
|
from ||= application_mailer_default_from
|
32
32
|
from ||= mailer_config_from_address
|
33
|
-
from ||= "reports@#{ENV['HOST'].
|
33
|
+
from ||= "reports@#{ENV['HOST'].delete_prefix('www.')}" if ENV['HOST'].present?
|
34
34
|
|
35
35
|
from || 'reports@example.com'
|
36
36
|
end
|
@@ -44,7 +44,7 @@ module Motor
|
|
44
44
|
def mailer_config_from_address
|
45
45
|
return if Rails.application.config.action_mailer.default_url_options&.dig(:host).blank?
|
46
46
|
|
47
|
-
"reports@#{Rails.application.config.action_mailer.default_url_options[:host].
|
47
|
+
"reports@#{Rails.application.config.action_mailer.default_url_options[:host].delete_prefix('www.')}"
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
data/app/models/motor/alert.rb
CHANGED
@@ -11,6 +11,7 @@ module Motor
|
|
11
11
|
has_many :taggable_tags, as: :taggable, dependent: :destroy
|
12
12
|
has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
|
13
13
|
|
14
|
+
attribute :preferences, default: -> { HashWithIndifferentAccess.new }
|
14
15
|
serialize :preferences, HashSerializer
|
15
16
|
|
16
17
|
scope :active, -> { where(deleted_at: nil) }
|
@@ -9,6 +9,7 @@ module Motor
|
|
9
9
|
has_many :taggable_tags, as: :taggable, dependent: :destroy
|
10
10
|
has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
|
11
11
|
|
12
|
+
attribute :preferences, default: -> { HashWithIndifferentAccess.new }
|
12
13
|
serialize :preferences, HashSerializer
|
13
14
|
|
14
15
|
scope :active, -> { where(deleted_at: nil) }
|
data/app/models/motor/form.rb
CHANGED
@@ -9,6 +9,7 @@ module Motor
|
|
9
9
|
has_many :taggable_tags, as: :taggable, dependent: :destroy
|
10
10
|
has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
|
11
11
|
|
12
|
+
attribute :preferences, default: -> { HashWithIndifferentAccess.new }
|
12
13
|
serialize :preferences, HashSerializer
|
13
14
|
|
14
15
|
scope :active, -> { where(deleted_at: nil) }
|
data/app/models/motor/query.rb
CHANGED
@@ -10,6 +10,7 @@ module Motor
|
|
10
10
|
has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
|
11
11
|
has_many :alerts, dependent: :destroy
|
12
12
|
|
13
|
+
attribute :preferences, default: -> { HashWithIndifferentAccess.new }
|
13
14
|
serialize :preferences, HashSerializer
|
14
15
|
|
15
16
|
scope :active, -> { where(deleted_at: nil) }
|
data/app/models/motor/tag.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<%= raw(Motor::Configs::BuildUiAppTag.call) %>
|
1
|
+
<%= raw(Motor::Configs::BuildUiAppTag.call(current_user)) %>
|
data/config/routes.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Motor::Admin.routes.draw do
|
4
4
|
namespace :motor, path: '' do
|
5
|
-
scope 'api', as:
|
5
|
+
scope 'api', as: :api do
|
6
6
|
resources :run_queries, only: %i[show create]
|
7
7
|
resources :send_alerts, only: %i[create]
|
8
8
|
resources :queries, only: %i[index show create update destroy]
|
@@ -34,16 +34,15 @@ Motor::Admin.routes.draw do
|
|
34
34
|
|
35
35
|
get '/', to: 'ui#show'
|
36
36
|
|
37
|
-
scope as:
|
37
|
+
scope as: :ui do
|
38
|
+
get '/data(/*path)', to: 'ui#index', as: :data
|
39
|
+
|
38
40
|
with_options controller: 'ui' do
|
39
|
-
resources :data, only: %i[index show],
|
40
|
-
param: 'path',
|
41
|
-
constraints: { path: /.+/ }
|
42
41
|
resources :reports, only: %i[index show]
|
43
|
-
resources :queries, only: %i[index show]
|
44
|
-
resources :dashboards, only: %i[index show]
|
45
|
-
resources :alerts, only: %i[index show]
|
46
|
-
resources :forms, only: %i[index show]
|
42
|
+
resources :queries, only: %i[index show new]
|
43
|
+
resources :dashboards, only: %i[index show new]
|
44
|
+
resources :alerts, only: %i[index show new]
|
45
|
+
resources :forms, only: %i[index show new]
|
47
46
|
end
|
48
47
|
end
|
49
48
|
end
|
@@ -1,62 +1,65 @@
|
|
1
1
|
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
2
2
|
def self.up
|
3
3
|
create_table :motor_queries do |t|
|
4
|
-
t.column :name, :
|
5
|
-
t.column :description, :
|
6
|
-
t.column :sql_body, :
|
7
|
-
t.column :preferences, :
|
8
|
-
t.column :author_id, :
|
9
|
-
t.column :author_type, :
|
4
|
+
t.column :name, :text, null: false
|
5
|
+
t.column :description, :text
|
6
|
+
t.column :sql_body, :text, null: false
|
7
|
+
t.column :preferences, :text, null: false
|
8
|
+
t.column :author_id, :bigint
|
9
|
+
t.column :author_type, :text
|
10
10
|
t.column :deleted_at, :datetime
|
11
11
|
|
12
12
|
t.timestamps
|
13
13
|
|
14
14
|
t.index :updated_at
|
15
|
-
t.index '
|
16
|
-
name: '
|
15
|
+
t.index 'name',
|
16
|
+
name: 'motor_queries_name_unique_index',
|
17
17
|
unique: true,
|
18
|
-
where: 'deleted_at IS NULL'
|
18
|
+
where: 'deleted_at IS NULL',
|
19
|
+
length: { name: 255 }
|
19
20
|
end
|
20
21
|
|
21
22
|
create_table :motor_dashboards do |t|
|
22
|
-
t.column :title, :
|
23
|
-
t.column :description, :
|
24
|
-
t.column :preferences, :
|
25
|
-
t.column :author_id, :
|
26
|
-
t.column :author_type, :
|
23
|
+
t.column :title, :text, null: false
|
24
|
+
t.column :description, :text
|
25
|
+
t.column :preferences, :text, null: false
|
26
|
+
t.column :author_id, :bigint
|
27
|
+
t.column :author_type, :text
|
27
28
|
t.column :deleted_at, :datetime
|
28
29
|
|
29
30
|
t.timestamps
|
30
31
|
|
31
32
|
t.index :updated_at
|
32
|
-
t.index '
|
33
|
-
name: '
|
33
|
+
t.index 'title',
|
34
|
+
name: 'motor_dashboards_title_unique_index',
|
34
35
|
unique: true,
|
35
|
-
where: 'deleted_at IS NULL'
|
36
|
+
where: 'deleted_at IS NULL',
|
37
|
+
length: { title: 255 }
|
36
38
|
end
|
37
39
|
|
38
40
|
create_table :motor_forms do |t|
|
39
|
-
t.column :name, :
|
40
|
-
t.column :description, :
|
41
|
-
t.column :api_path, :
|
42
|
-
t.column :http_method, :
|
43
|
-
t.column :preferences, :
|
44
|
-
t.column :author_id, :
|
45
|
-
t.column :author_type, :
|
41
|
+
t.column :name, :text, null: false
|
42
|
+
t.column :description, :text
|
43
|
+
t.column :api_path, :text, null: false
|
44
|
+
t.column :http_method, :text, null: false
|
45
|
+
t.column :preferences, :text, null: false
|
46
|
+
t.column :author_id, :bigint
|
47
|
+
t.column :author_type, :text
|
46
48
|
t.column :deleted_at, :datetime
|
47
49
|
|
48
50
|
t.timestamps
|
49
51
|
|
50
52
|
t.index :updated_at
|
51
|
-
t.index '
|
52
|
-
name: '
|
53
|
+
t.index 'name',
|
54
|
+
name: 'motor_forms_name_unique_index',
|
53
55
|
unique: true,
|
54
|
-
where: 'deleted_at IS NULL'
|
56
|
+
where: 'deleted_at IS NULL',
|
57
|
+
length: { name: 255 }
|
55
58
|
end
|
56
59
|
|
57
60
|
create_table :motor_resources do |t|
|
58
|
-
t.column :name, :
|
59
|
-
t.column :preferences, :
|
61
|
+
t.column :name, :text, null: false, index: { unique: true, length: 255 }
|
62
|
+
t.column :preferences, :text, null: false
|
60
63
|
|
61
64
|
t.timestamps
|
62
65
|
|
@@ -64,8 +67,8 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
64
67
|
end
|
65
68
|
|
66
69
|
create_table :motor_configs do |t|
|
67
|
-
t.column :key, :
|
68
|
-
t.column :value, :
|
70
|
+
t.column :key, :text, null: false, index: { unique: true, length: 255 }
|
71
|
+
t.column :value, :text, null: false
|
69
72
|
|
70
73
|
t.timestamps
|
71
74
|
|
@@ -74,74 +77,80 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
74
77
|
|
75
78
|
create_table :motor_alerts do |t|
|
76
79
|
t.references :query, null: false, foreign_key: { to_table: :motor_queries }, index: true
|
77
|
-
t.column :name, :
|
78
|
-
t.column :description, :
|
79
|
-
t.column :to_emails, :
|
80
|
+
t.column :name, :text, null: false
|
81
|
+
t.column :description, :text
|
82
|
+
t.column :to_emails, :text, null: false
|
80
83
|
t.column :is_enabled, :boolean, null: false, default: true
|
81
|
-
t.column :preferences, :
|
82
|
-
t.column :author_id, :
|
83
|
-
t.column :author_type, :
|
84
|
+
t.column :preferences, :text, null: false
|
85
|
+
t.column :author_id, :bigint
|
86
|
+
t.column :author_type, :text
|
84
87
|
t.column :deleted_at, :datetime
|
85
88
|
|
86
89
|
t.timestamps
|
87
90
|
|
88
91
|
t.index :updated_at
|
89
|
-
t.index '
|
90
|
-
name: '
|
92
|
+
t.index 'name',
|
93
|
+
name: 'motor_alerts_name_unique_index',
|
91
94
|
unique: true,
|
92
|
-
where: 'deleted_at IS NULL'
|
95
|
+
where: 'deleted_at IS NULL',
|
96
|
+
length: { name: 255 }
|
93
97
|
end
|
94
98
|
|
95
99
|
create_table :motor_alert_locks do |t|
|
96
100
|
t.references :alert, null: false, foreign_key: { to_table: :motor_alerts }
|
97
|
-
t.column :lock_timestamp, :
|
101
|
+
t.column :lock_timestamp, :text, null: false
|
98
102
|
|
99
103
|
t.timestamps
|
100
104
|
|
101
|
-
t.index %i[alert_id lock_timestamp], unique: true
|
105
|
+
t.index %i[alert_id lock_timestamp], unique: true, length: { lock_timestamp: 255 }
|
102
106
|
end
|
103
107
|
|
104
108
|
create_table :motor_tags do |t|
|
105
|
-
t.column :name, :
|
109
|
+
t.column :name, :text, null: false
|
106
110
|
|
107
111
|
t.timestamps
|
108
112
|
|
109
|
-
t.index '
|
110
|
-
name: '
|
111
|
-
unique: true
|
113
|
+
t.index 'name',
|
114
|
+
name: 'motor_tags_name_unique_index',
|
115
|
+
unique: true,
|
116
|
+
length: { name: 255 }
|
112
117
|
end
|
113
118
|
|
114
119
|
create_table :motor_taggable_tags do |t|
|
115
120
|
t.references :tag, null: false, foreign_key: { to_table: :motor_tags }, index: true
|
116
|
-
t.column :taggable_id, :
|
117
|
-
t.column :taggable_type, :
|
121
|
+
t.column :taggable_id, :bigint, null: false
|
122
|
+
t.column :taggable_type, :text, null: false
|
118
123
|
|
119
124
|
t.index %i[taggable_id taggable_type tag_id],
|
120
125
|
name: 'motor_polymorphic_association_tag_index',
|
121
|
-
unique: true
|
126
|
+
unique: true,
|
127
|
+
length: { taggable_type: 255 }
|
122
128
|
end
|
123
129
|
|
124
130
|
create_table :motor_audits do |t|
|
125
|
-
t.column :auditable_id, :
|
126
|
-
t.column :auditable_type, :
|
127
|
-
t.column :associated_id, :
|
128
|
-
t.column :associated_type, :
|
129
|
-
t.column :user_id, :
|
130
|
-
t.column :user_type, :
|
131
|
-
t.column :username, :
|
132
|
-
t.column :action, :
|
131
|
+
t.column :auditable_id, :bigint
|
132
|
+
t.column :auditable_type, :text
|
133
|
+
t.column :associated_id, :bigint
|
134
|
+
t.column :associated_type, :text
|
135
|
+
t.column :user_id, :bigint
|
136
|
+
t.column :user_type, :text
|
137
|
+
t.column :username, :text
|
138
|
+
t.column :action, :text
|
133
139
|
t.column :audited_changes, :text
|
134
|
-
t.column :version, :
|
135
|
-
t.column :comment, :
|
136
|
-
t.column :remote_address, :
|
137
|
-
t.column :request_uuid, :
|
140
|
+
t.column :version, :bigint, default: 0
|
141
|
+
t.column :comment, :text
|
142
|
+
t.column :remote_address, :text
|
143
|
+
t.column :request_uuid, :text
|
138
144
|
t.column :created_at, :datetime
|
139
145
|
end
|
140
146
|
|
141
|
-
add_index :motor_audits, %i[auditable_type auditable_id version], name: 'motor_auditable_index'
|
142
|
-
|
143
|
-
add_index :motor_audits, %i[
|
144
|
-
|
147
|
+
add_index :motor_audits, %i[auditable_type auditable_id version], name: 'motor_auditable_index',
|
148
|
+
length: { auditable_type: 255 }
|
149
|
+
add_index :motor_audits, %i[associated_type associated_id], name: 'motor_auditable_associated_index',
|
150
|
+
length: { associated_type: 255 }
|
151
|
+
add_index :motor_audits, %i[user_id user_type], name: 'motor_auditable_user_index',
|
152
|
+
length: { user_type: 255 }
|
153
|
+
add_index :motor_audits, :request_uuid, length: { request_uuid: 255 }
|
145
154
|
add_index :motor_audits, :created_at
|
146
155
|
end
|
147
156
|
|
data/lib/motor.rb
CHANGED
@@ -40,7 +40,6 @@ module Motor
|
|
40
40
|
(defined?(::Puma) && File.basename($PROGRAM_NAME) == 'puma') ||
|
41
41
|
defined?(::Unicorn::HttpServer) ||
|
42
42
|
defined?(::Mongrel::HttpServer) ||
|
43
|
-
defined?(::WEBrick::VERSION) ||
|
44
43
|
defined?(JRuby::Rack::VERSION) ||
|
45
44
|
defined?(::Trinidad::Server)
|
46
45
|
end
|
@@ -1,6 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Motor
|
4
|
+
module ActiveRecordUtils
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def reset_id_sequence!(model)
|
8
|
+
case ActiveRecord::Base.connection.class.name
|
9
|
+
when 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
|
10
|
+
ActiveRecord::Base.connection.reset_pk_sequence!(model.table_name)
|
11
|
+
else
|
12
|
+
ActiveRecord::Base.connection.reset_sequence!(model.table_name, 'id')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
4
16
|
end
|
5
17
|
|
6
18
|
require_relative './active_record_utils/types'
|
@@ -13,6 +13,10 @@ module Motor
|
|
13
13
|
super(**hash.with_indifferent_access.slice(*KEYWORD_ARGS).symbolize_keys)
|
14
14
|
end
|
15
15
|
|
16
|
+
def create_after_upload!(hash)
|
17
|
+
super(**hash.with_indifferent_access.slice(*KEYWORD_ARGS).symbolize_keys)
|
18
|
+
end
|
19
|
+
|
16
20
|
def create_after_unfurling!(hash)
|
17
21
|
super(**hash.with_indifferent_access.slice(*KEYWORD_ARGS).symbolize_keys)
|
18
22
|
end
|
data/lib/motor/admin.rb
CHANGED
@@ -43,7 +43,7 @@ module Motor
|
|
43
43
|
end
|
44
44
|
|
45
45
|
initializer 'motor.alerts.scheduler' do
|
46
|
-
config.after_initialize do
|
46
|
+
config.after_initialize do
|
47
47
|
next unless Motor.server?
|
48
48
|
|
49
49
|
Motor::Alerts::Scheduler::SCHEDULER_TASK.execute
|
@@ -66,13 +66,12 @@ module Motor
|
|
66
66
|
end
|
67
67
|
|
68
68
|
initializer 'motor.active_storage.extensions' do
|
69
|
-
|
70
|
-
ActiveStorage::Attachment.include(Motor::ActiveRecordUtils::ActiveStorageLinksExtension)
|
71
|
-
end
|
69
|
+
next unless defined?(ActiveStorage::Engine)
|
72
70
|
|
73
|
-
|
74
|
-
|
75
|
-
|
71
|
+
ActiveStorage::Engine.eager_load!
|
72
|
+
|
73
|
+
ActiveStorage::Attachment.include(Motor::ActiveRecordUtils::ActiveStorageLinksExtension)
|
74
|
+
ActiveStorage::Blob.singleton_class.prepend(Motor::ActiveRecordUtils::ActiveStorageBlobPatch)
|
76
75
|
end
|
77
76
|
end
|
78
77
|
end
|
@@ -28,7 +28,7 @@ module Motor
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def create_from_params!(params, current_user = nil)
|
31
|
-
raise NameAlreadyExists if Alert.exists?(
|
31
|
+
raise NameAlreadyExists if Alert.exists?(name: params[:name])
|
32
32
|
|
33
33
|
alert = build_from_params(params, current_user)
|
34
34
|
|
@@ -77,7 +77,7 @@ module Motor
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def archive_with_existing_name(alert)
|
80
|
-
Motor::Alert.where(['
|
80
|
+
Motor::Alert.where(['name = ? AND id != ?', alert.name, alert.id])
|
81
81
|
.update_all(deleted_at: Time.current)
|
82
82
|
end
|
83
83
|
|
@@ -87,9 +87,9 @@ module Motor
|
|
87
87
|
|
88
88
|
def name_already_exists?(alert)
|
89
89
|
if alert.new_record?
|
90
|
-
Alert.exists?(
|
90
|
+
Alert.exists?(name: alert.name)
|
91
91
|
else
|
92
|
-
Alert.exists?(['
|
92
|
+
Alert.exists?(['name = ? AND id != ?', alert.name, alert.id])
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
@@ -10,12 +10,12 @@ module Motor
|
|
10
10
|
|
11
11
|
rel = rel.preload_associations_lazily if rel.is_a?(ActiveRecord::Relation)
|
12
12
|
|
13
|
-
json_params = {}
|
13
|
+
json_params = {}.with_indifferent_access
|
14
14
|
|
15
15
|
assign_include_params(json_params, rel, params)
|
16
16
|
assign_fields_params(json_params, rel, params)
|
17
17
|
|
18
|
-
rel.as_json(json_params
|
18
|
+
rel.as_json(json_params)
|
19
19
|
end
|
20
20
|
|
21
21
|
def assign_include_params(json_params, _rel, api_params)
|
@@ -51,11 +51,11 @@ module Motor
|
|
51
51
|
params[:fields].each do |key, fields|
|
52
52
|
fields = fields.split(',') if fields.is_a?(String)
|
53
53
|
|
54
|
-
merge_fields_params!(key, fields,
|
54
|
+
merge_fields_params!(json_params, key, fields, model)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
def merge_fields_params!(key, fields,
|
58
|
+
def merge_fields_params!(json_params, key, fields, model)
|
59
59
|
model_name = model.name.underscore
|
60
60
|
|
61
61
|
if key == model_name || model_name.split('/').last == key
|
@@ -96,8 +96,8 @@ module Motor
|
|
96
96
|
def normalize_include_params(params)
|
97
97
|
case params
|
98
98
|
when Array
|
99
|
-
params.
|
100
|
-
|
99
|
+
params.index_with do |_|
|
100
|
+
{ 'include' => {} }
|
101
101
|
end
|
102
102
|
when String
|
103
103
|
{ params => { 'include' => {} } }
|
@@ -57,13 +57,7 @@ module Motor
|
|
57
57
|
def find_searchable_columns(model)
|
58
58
|
model.columns.map do |column|
|
59
59
|
next unless column.type.in?(COLUMN_TYPES)
|
60
|
-
|
61
|
-
has_inclusion_validator =
|
62
|
-
model.validators_on(column.name).any? do |e|
|
63
|
-
e.is_a?(ActiveModel::Validations::InclusionValidator)
|
64
|
-
end
|
65
|
-
|
66
|
-
next if has_inclusion_validator
|
60
|
+
next if model.validators_on(column.name).any?(ActiveModel::Validations::InclusionValidator)
|
67
61
|
|
68
62
|
column.name
|
69
63
|
end.compact
|
data/lib/motor/api_query/sort.rb
CHANGED
@@ -13,7 +13,9 @@ module Motor
|
|
13
13
|
arel_order = build_arel_order(rel.klass, param)
|
14
14
|
join_params = build_join_params(rel.klass, param)
|
15
15
|
|
16
|
-
rel.
|
16
|
+
rel = rel.left_joins(join_params) if join_params.present?
|
17
|
+
|
18
|
+
rel.reorder(arel_order)
|
17
19
|
end
|
18
20
|
|
19
21
|
def build_join_params(_model, param)
|
data/lib/motor/assets.rb
CHANGED
@@ -12,6 +12,8 @@ module Motor
|
|
12
12
|
models.map do |model|
|
13
13
|
Object.const_get(model.name)
|
14
14
|
|
15
|
+
next unless ActiveRecord::Base.connection.table_exists?(model.table_name)
|
16
|
+
|
15
17
|
schema = build_model_schema(model)
|
16
18
|
|
17
19
|
if model.respond_to?(:devise_modules)
|
@@ -20,7 +22,7 @@ module Motor
|
|
20
22
|
|
21
23
|
schema
|
22
24
|
rescue StandardError, NotImplementedError => e
|
23
|
-
Rails.logger.error(e)
|
25
|
+
Rails.logger.error(e)
|
24
26
|
|
25
27
|
next
|
26
28
|
end.compact
|
@@ -34,6 +36,7 @@ module Motor
|
|
34
36
|
models -= Motor::ApplicationRecord.descendants
|
35
37
|
models -= [Motor::Audit]
|
36
38
|
models -= [ActiveRecord::SchemaMigration] if defined?(ActiveRecord::SchemaMigration)
|
39
|
+
models -= [ActiveRecord::InternalMetadata] if defined?(ActiveRecord::InternalMetadata)
|
37
40
|
models -= [ActiveStorage::Blob] if defined?(ActiveStorage::Blob)
|
38
41
|
models -= [ActiveStorage::VariantRecord] if defined?(ActiveStorage::VariantRecord)
|
39
42
|
|
@@ -101,7 +104,7 @@ module Motor
|
|
101
104
|
name: column.name,
|
102
105
|
display_name: Utils.humanize_column_name(column.name),
|
103
106
|
column_type: is_enum ? 'string' : UNIFIED_TYPES[column.type.to_s] || column.type.to_s,
|
104
|
-
is_array: column.array?,
|
107
|
+
is_array: column.respond_to?(:array?) && column.array?,
|
105
108
|
access_type: COLUMN_NAME_ACCESS_TYPES.fetch(column.name, ColumnAccessTypes::READ_WRITE),
|
106
109
|
default_value: default_attrs[column.name],
|
107
110
|
validators: fetch_validators(model, column.name),
|
@@ -12,21 +12,21 @@ module Motor
|
|
12
12
|
|
13
13
|
module_function
|
14
14
|
|
15
|
-
def call
|
15
|
+
def call(current_user = nil)
|
16
16
|
cache_keys = LoadFromCache.load_cache_keys
|
17
17
|
|
18
|
-
CACHE_STORE.fetch(cache_keys.hash) do
|
18
|
+
CACHE_STORE.fetch("#{cache_keys.hash}#{current_user&.id}") do
|
19
19
|
CACHE_STORE.clear
|
20
20
|
|
21
|
-
Motor::ApplicationController.helpers.
|
22
|
-
:div, '', id: 'app', data: build_data(cache_keys)
|
23
|
-
)
|
21
|
+
Motor::ApplicationController.helpers.tag.div('', id: 'app', data: build_data(cache_keys, current_user))
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|
27
25
|
# @return [Hash]
|
28
|
-
def build_data(cache_keys = {})
|
26
|
+
def build_data(cache_keys = {}, current_user = nil)
|
29
27
|
{
|
28
|
+
current_user: current_user&.as_json(only: %i[id email]),
|
29
|
+
audits_count: Motor::Audit.count,
|
30
30
|
base_path: Motor::Admin.routes.url_helpers.motor_path,
|
31
31
|
schema: Motor::BuildSchema.call(cache_keys),
|
32
32
|
header_links: header_links_data_hash(cache_keys[:configs]),
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Motor
|
4
4
|
module Configs
|
5
5
|
module LoadFromCache
|
6
|
-
|
6
|
+
CACHE_HASH = HashWithIndifferentAccess.new
|
7
7
|
|
8
8
|
module_function
|
9
9
|
|
@@ -56,25 +56,37 @@ module Motor
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
def maybe_fetch_from_cache(type, cache_key
|
60
|
-
return
|
59
|
+
def maybe_fetch_from_cache(type, cache_key)
|
60
|
+
return yield unless cache_key
|
61
61
|
|
62
|
-
|
62
|
+
if CACHE_HASH[type] && CACHE_HASH[type][:key] == cache_key
|
63
|
+
CACHE_HASH[type][:value]
|
64
|
+
else
|
65
|
+
result = yield
|
66
|
+
|
67
|
+
CACHE_HASH[type] = { key: cache_key, value: result }
|
68
|
+
|
69
|
+
result
|
70
|
+
end
|
63
71
|
end
|
64
72
|
|
65
73
|
def load_cache_keys
|
66
|
-
ActiveRecord::Base.connection.execute(
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
result = ActiveRecord::Base.connection.execute(cache_keys_sql).to_a
|
75
|
+
|
76
|
+
result = result.map(&:values) if result.first.is_a?(Hash)
|
77
|
+
|
78
|
+
result.to_h.with_indifferent_access
|
79
|
+
end
|
80
|
+
|
81
|
+
def cache_keys_sql
|
82
|
+
[
|
83
|
+
Motor::Config.select("'configs', MAX(updated_at)").to_sql,
|
84
|
+
Motor::Resource.select("'resources', MAX(updated_at)").to_sql,
|
85
|
+
Motor::Dashboard.select("'dashboards', MAX(updated_at)").to_sql,
|
86
|
+
Motor::Alert.select("'alerts', MAX(updated_at)").to_sql,
|
87
|
+
Motor::Query.select("'queries', MAX(updated_at)").to_sql,
|
88
|
+
Motor::Form.select("'forms', MAX(updated_at)").to_sql
|
89
|
+
].join(' UNION ')
|
78
90
|
end
|
79
91
|
end
|
80
92
|
end
|
@@ -87,7 +87,7 @@ module Motor
|
|
87
87
|
|
88
88
|
archive_taggable_items(records - processed_records, configs_timestamp)
|
89
89
|
|
90
|
-
|
90
|
+
ActiveRecordUtils.reset_id_sequence!(records.klass)
|
91
91
|
end
|
92
92
|
|
93
93
|
def update_taggable_items(records, config_items, update_proc)
|
@@ -9,7 +9,7 @@ module Motor
|
|
9
9
|
module_function
|
10
10
|
|
11
11
|
def call(remote_url, api_key)
|
12
|
-
url = remote_url.
|
12
|
+
url = remote_url.delete_suffix('/') + Motor::Configs::SYNC_API_PATH
|
13
13
|
|
14
14
|
sync_from_remote!(url, api_key)
|
15
15
|
sync_to_remote!(url, api_key)
|
@@ -16,7 +16,7 @@ module Motor
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def create_from_params!(params, current_user = nil)
|
19
|
-
raise TitleAlreadyExists if Dashboard.exists?(
|
19
|
+
raise TitleAlreadyExists if Dashboard.exists?(title: params[:title])
|
20
20
|
|
21
21
|
dashboard = build_from_params(params, current_user)
|
22
22
|
|
@@ -57,15 +57,15 @@ module Motor
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def archive_with_existing_name(dashboard)
|
60
|
-
Motor::Dashboard.where(['
|
60
|
+
Motor::Dashboard.where(['title = ? AND id != ?', dashboard.title, dashboard.id])
|
61
61
|
.update_all(deleted_at: Time.current)
|
62
62
|
end
|
63
63
|
|
64
64
|
def title_already_exists?(dashboard)
|
65
65
|
if dashboard.new_record?
|
66
|
-
Motor::Dashboard.exists?(
|
66
|
+
Motor::Dashboard.exists?(title: dashboard.title)
|
67
67
|
else
|
68
|
-
Motor::Dashboard.exists?(['
|
68
|
+
Motor::Dashboard.exists?(['title = ? AND id != ?', dashboard.title, dashboard.id])
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -16,7 +16,7 @@ module Motor
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def create_from_params!(params, current_user = nil)
|
19
|
-
raise NameAlreadyExists if Form.exists?(
|
19
|
+
raise NameAlreadyExists if Form.exists?(name: params[:name])
|
20
20
|
|
21
21
|
form = build_from_params(params, current_user)
|
22
22
|
|
@@ -57,15 +57,15 @@ module Motor
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def archive_with_existing_name(form)
|
60
|
-
Motor::Form.where(['
|
60
|
+
Motor::Form.where(['name = ? AND id != ?', form.name, form.id])
|
61
61
|
.update_all(deleted_at: Time.current)
|
62
62
|
end
|
63
63
|
|
64
64
|
def name_already_exists?(form)
|
65
65
|
if form.new_record?
|
66
|
-
Motor::Form.exists?(['
|
66
|
+
Motor::Form.exists?(['name = ?', form.name])
|
67
67
|
else
|
68
|
-
Motor::Form.exists?(['
|
68
|
+
Motor::Form.exists?(['name = ? AND id != ?', form.name, form.id])
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -16,7 +16,7 @@ module Motor
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def create_from_params!(params, current_user = nil)
|
19
|
-
raise NameAlreadyExists if Query.exists?(
|
19
|
+
raise NameAlreadyExists if Query.exists?(name: params[:name])
|
20
20
|
|
21
21
|
query = build_from_params(params, current_user)
|
22
22
|
|
@@ -57,15 +57,15 @@ module Motor
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def archive_with_existing_name(query)
|
60
|
-
Motor::Query.where(['
|
60
|
+
Motor::Query.where(['name = ? AND id != ?', query.name, query.id])
|
61
61
|
.update_all(deleted_at: Time.current)
|
62
62
|
end
|
63
63
|
|
64
64
|
def name_already_exists?(query)
|
65
65
|
if query.new_record?
|
66
|
-
Query.exists?(
|
66
|
+
Query.exists?(name: query.name)
|
67
67
|
else
|
68
|
-
Query.exists?(['
|
68
|
+
Query.exists?(['name = ? AND id != ?', query.name, query.id])
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -35,8 +35,8 @@ module Motor
|
|
35
35
|
|
36
36
|
ActiveRecord::Base.transaction do
|
37
37
|
result =
|
38
|
-
case ActiveRecord::Base.connection
|
39
|
-
when ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
38
|
+
case ActiveRecord::Base.connection.class.name
|
39
|
+
when 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
|
40
40
|
PostgresqlExecQuery.call(ActiveRecord::Base.connection, statement)
|
41
41
|
else
|
42
42
|
ActiveRecord::Base.connection.exec_query(*statement)
|
@@ -73,7 +73,7 @@ module Motor
|
|
73
73
|
|
74
74
|
attributes = build_statement_attributes(query_variables)
|
75
75
|
|
76
|
-
[format(WITH_STATEMENT_TEMPLATE, sql_body: sql.strip.
|
76
|
+
[format(WITH_STATEMENT_TEMPLATE, sql_body: sql.strip.delete_suffix(';'), limit: limit), 'SQL', attributes]
|
77
77
|
end
|
78
78
|
|
79
79
|
# @param variables [Array<(String, Object)>]
|
data/lib/motor/tags.rb
CHANGED
@@ -8,9 +8,9 @@ module Motor
|
|
8
8
|
return taggable unless tags
|
9
9
|
|
10
10
|
tags.each do |tag_name|
|
11
|
-
next if taggable.taggable_tags.find { |tt| tt.tag.name.
|
11
|
+
next if taggable.taggable_tags.find { |tt| tt.tag.name.casecmp(tag_name).zero? }
|
12
12
|
|
13
|
-
tag = Tag.
|
13
|
+
tag = Tag.find_or_initialize_by(name: tag_name)
|
14
14
|
|
15
15
|
taggable.taggable_tags.new(tag: tag)
|
16
16
|
end
|
data/lib/motor/tasks/motor.rake
CHANGED
data/lib/motor/version.rb
CHANGED
Binary file
|
Binary file
|
data/ui/dist/manifest.json
CHANGED
@@ -2068,11 +2068,11 @@
|
|
2068
2068
|
"mail-opened.svg": "icons/mail-opened.svg",
|
2069
2069
|
"mail.svg": "icons/mail.svg",
|
2070
2070
|
"mailbox.svg": "icons/mailbox.svg",
|
2071
|
-
"main-
|
2072
|
-
"main-
|
2073
|
-
"main-
|
2074
|
-
"main.css": "main-
|
2075
|
-
"main.js": "main-
|
2071
|
+
"main-36a9ee6a9b0427a77d87.css.gz": "main-36a9ee6a9b0427a77d87.css.gz",
|
2072
|
+
"main-36a9ee6a9b0427a77d87.js.LICENSE.txt": "main-36a9ee6a9b0427a77d87.js.LICENSE.txt",
|
2073
|
+
"main-36a9ee6a9b0427a77d87.js.gz": "main-36a9ee6a9b0427a77d87.js.gz",
|
2074
|
+
"main.css": "main-36a9ee6a9b0427a77d87.css",
|
2075
|
+
"main.js": "main-36a9ee6a9b0427a77d87.js",
|
2076
2076
|
"man.svg": "icons/man.svg",
|
2077
2077
|
"manual-gearbox.svg": "icons/manual-gearbox.svg",
|
2078
2078
|
"map-2.svg": "icons/map-2.svg",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motor-admin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.52
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pete Matsyburka
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
11
|
+
date: 2021-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord-filter
|
@@ -118,6 +118,7 @@ files:
|
|
118
118
|
- LICENSE
|
119
119
|
- README.md
|
120
120
|
- Rakefile
|
121
|
+
- app/controllers/concerns/motor/current_user_method.rb
|
121
122
|
- app/controllers/concerns/motor/load_and_authorize_dynamic_resource.rb
|
122
123
|
- app/controllers/concerns/motor/wrap_io_params.rb
|
123
124
|
- app/controllers/motor/active_storage_attachments_controller.rb
|
@@ -1480,8 +1481,8 @@ files:
|
|
1480
1481
|
- ui/dist/icons/zoom-money.svg.gz
|
1481
1482
|
- ui/dist/icons/zoom-out.svg.gz
|
1482
1483
|
- ui/dist/icons/zoom-question.svg.gz
|
1483
|
-
- ui/dist/main-
|
1484
|
-
- ui/dist/main-
|
1484
|
+
- ui/dist/main-36a9ee6a9b0427a77d87.css.gz
|
1485
|
+
- ui/dist/main-36a9ee6a9b0427a77d87.js.gz
|
1485
1486
|
- ui/dist/manifest.json
|
1486
1487
|
homepage:
|
1487
1488
|
licenses:
|
Binary file
|