motor-admin 0.1.52 → 0.1.53
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/motor/run_queries_controller.rb +10 -8
- data/app/models/motor/query.rb +1 -1
- data/lib/generators/motor/templates/install.rb +32 -41
- data/lib/motor/admin.rb +5 -5
- data/lib/motor/assets.rb +2 -0
- data/lib/motor/queries/run_query.rb +24 -3
- data/lib/motor/version.rb +1 -1
- data/ui/dist/main-67fbb3a8f6a6388434c8.css.gz +0 -0
- data/ui/dist/main-67fbb3a8f6a6388434c8.js.gz +0 -0
- data/ui/dist/manifest.json +5 -5
- metadata +9 -6
- data/ui/dist/main-36a9ee6a9b0427a77d87.css.gz +0 -0
- data/ui/dist/main-36a9ee6a9b0427a77d87.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: 2484e6d98ef1891e59ab7bc0e50dc8337f0b99ae3fb35e2d5d72caf84020112c
|
4
|
+
data.tar.gz: 85a1e6334f83ccdd8e49b6f80ef52ff7ef8f169b586fc00b0745d281e1b75f9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dabb17786ed10544c54246f0a460cb3507d9cca5cb8269aa4e0cf0962d69f55cb8f63870f0c6ecfe2810da7c174f2cce7f75702f3472be0221a02ad49babb159
|
7
|
+
data.tar.gz: 2a5c5b2c319248b692f6d662c510ca489066a192c613714c9e970352db3a06994d032d01052707799627bf81bca0b6422a399f8584925baa1658d44706043c67
|
@@ -9,22 +9,24 @@ module Motor
|
|
9
9
|
before_action :build_query, only: :create
|
10
10
|
authorize_resource :query, only: :create
|
11
11
|
|
12
|
-
rescue_from 'ActiveRecord::StatementInvalid' do |e|
|
13
|
-
render json: { errors: [{ detail: e.message }] }, status: :unprocessable_entity
|
14
|
-
end
|
15
|
-
|
16
12
|
def show
|
17
|
-
|
13
|
+
render_result
|
18
14
|
end
|
19
15
|
|
20
16
|
def create
|
21
|
-
|
17
|
+
render_result
|
22
18
|
end
|
23
19
|
|
24
20
|
private
|
25
21
|
|
26
|
-
def
|
27
|
-
Queries::RunQuery.call(@query, variables_hash: params[:variables])
|
22
|
+
def render_result
|
23
|
+
query_result = Queries::RunQuery.call(@query, variables_hash: params[:variables])
|
24
|
+
|
25
|
+
if query_result.error
|
26
|
+
render json: { errors: [{ detail: query_result.error }] }, status: :unprocessable_entity
|
27
|
+
else
|
28
|
+
render json: query_result_hash(query_result)
|
29
|
+
end
|
28
30
|
end
|
29
31
|
|
30
32
|
def query_result_hash(query_result)
|
data/app/models/motor/query.rb
CHANGED
@@ -16,7 +16,7 @@ module Motor
|
|
16
16
|
scope :active, -> { where(deleted_at: nil) }
|
17
17
|
|
18
18
|
def result(variables_hash = {})
|
19
|
-
result = Motor::Queries::RunQuery.call(self, variables_hash: variables_hash)
|
19
|
+
result = Motor::Queries::RunQuery.call!(self, variables_hash: variables_hash)
|
20
20
|
column_names = result.columns.pluck(:name)
|
21
21
|
|
22
22
|
result.data.map { |row| column_names.zip(row).to_h }
|
@@ -1,12 +1,12 @@
|
|
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, :
|
4
|
+
t.column :name, :string, null: false
|
5
5
|
t.column :description, :text
|
6
6
|
t.column :sql_body, :text, null: false
|
7
7
|
t.column :preferences, :text, null: false
|
8
8
|
t.column :author_id, :bigint
|
9
|
-
t.column :author_type, :
|
9
|
+
t.column :author_type, :string
|
10
10
|
t.column :deleted_at, :datetime
|
11
11
|
|
12
12
|
t.timestamps
|
@@ -15,16 +15,15 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
15
15
|
t.index 'name',
|
16
16
|
name: 'motor_queries_name_unique_index',
|
17
17
|
unique: true,
|
18
|
-
where: 'deleted_at IS NULL'
|
19
|
-
length: { name: 255 }
|
18
|
+
where: 'deleted_at IS NULL'
|
20
19
|
end
|
21
20
|
|
22
21
|
create_table :motor_dashboards do |t|
|
23
|
-
t.column :title, :
|
22
|
+
t.column :title, :string, null: false
|
24
23
|
t.column :description, :text
|
25
24
|
t.column :preferences, :text, null: false
|
26
25
|
t.column :author_id, :bigint
|
27
|
-
t.column :author_type, :
|
26
|
+
t.column :author_type, :string
|
28
27
|
t.column :deleted_at, :datetime
|
29
28
|
|
30
29
|
t.timestamps
|
@@ -33,18 +32,17 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
33
32
|
t.index 'title',
|
34
33
|
name: 'motor_dashboards_title_unique_index',
|
35
34
|
unique: true,
|
36
|
-
where: 'deleted_at IS NULL'
|
37
|
-
length: { title: 255 }
|
35
|
+
where: 'deleted_at IS NULL'
|
38
36
|
end
|
39
37
|
|
40
38
|
create_table :motor_forms do |t|
|
41
|
-
t.column :name, :
|
39
|
+
t.column :name, :string, null: false
|
42
40
|
t.column :description, :text
|
43
41
|
t.column :api_path, :text, null: false
|
44
|
-
t.column :http_method, :
|
42
|
+
t.column :http_method, :string, null: false
|
45
43
|
t.column :preferences, :text, null: false
|
46
44
|
t.column :author_id, :bigint
|
47
|
-
t.column :author_type, :
|
45
|
+
t.column :author_type, :string
|
48
46
|
t.column :deleted_at, :datetime
|
49
47
|
|
50
48
|
t.timestamps
|
@@ -53,12 +51,11 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
53
51
|
t.index 'name',
|
54
52
|
name: 'motor_forms_name_unique_index',
|
55
53
|
unique: true,
|
56
|
-
where: 'deleted_at IS NULL'
|
57
|
-
length: { name: 255 }
|
54
|
+
where: 'deleted_at IS NULL'
|
58
55
|
end
|
59
56
|
|
60
57
|
create_table :motor_resources do |t|
|
61
|
-
t.column :name, :
|
58
|
+
t.column :name, :string, null: false, index: { unique: true }
|
62
59
|
t.column :preferences, :text, null: false
|
63
60
|
|
64
61
|
t.timestamps
|
@@ -67,7 +64,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
67
64
|
end
|
68
65
|
|
69
66
|
create_table :motor_configs do |t|
|
70
|
-
t.column :key, :
|
67
|
+
t.column :key, :string, null: false, index: { unique: true }
|
71
68
|
t.column :value, :text, null: false
|
72
69
|
|
73
70
|
t.timestamps
|
@@ -77,13 +74,13 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
77
74
|
|
78
75
|
create_table :motor_alerts do |t|
|
79
76
|
t.references :query, null: false, foreign_key: { to_table: :motor_queries }, index: true
|
80
|
-
t.column :name, :
|
77
|
+
t.column :name, :string, null: false
|
81
78
|
t.column :description, :text
|
82
79
|
t.column :to_emails, :text, null: false
|
83
80
|
t.column :is_enabled, :boolean, null: false, default: true
|
84
81
|
t.column :preferences, :text, null: false
|
85
82
|
t.column :author_id, :bigint
|
86
|
-
t.column :author_type, :
|
83
|
+
t.column :author_type, :string
|
87
84
|
t.column :deleted_at, :datetime
|
88
85
|
|
89
86
|
t.timestamps
|
@@ -92,65 +89,59 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
92
89
|
t.index 'name',
|
93
90
|
name: 'motor_alerts_name_unique_index',
|
94
91
|
unique: true,
|
95
|
-
where: 'deleted_at IS NULL'
|
96
|
-
length: { name: 255 }
|
92
|
+
where: 'deleted_at IS NULL'
|
97
93
|
end
|
98
94
|
|
99
95
|
create_table :motor_alert_locks do |t|
|
100
96
|
t.references :alert, null: false, foreign_key: { to_table: :motor_alerts }
|
101
|
-
t.column :lock_timestamp, :
|
97
|
+
t.column :lock_timestamp, :string, null: false
|
102
98
|
|
103
99
|
t.timestamps
|
104
100
|
|
105
|
-
t.index %i[alert_id lock_timestamp], unique: true
|
101
|
+
t.index %i[alert_id lock_timestamp], unique: true
|
106
102
|
end
|
107
103
|
|
108
104
|
create_table :motor_tags do |t|
|
109
|
-
t.column :name, :
|
105
|
+
t.column :name, :string, null: false
|
110
106
|
|
111
107
|
t.timestamps
|
112
108
|
|
113
109
|
t.index 'name',
|
114
110
|
name: 'motor_tags_name_unique_index',
|
115
|
-
unique: true
|
116
|
-
length: { name: 255 }
|
111
|
+
unique: true
|
117
112
|
end
|
118
113
|
|
119
114
|
create_table :motor_taggable_tags do |t|
|
120
115
|
t.references :tag, null: false, foreign_key: { to_table: :motor_tags }, index: true
|
121
116
|
t.column :taggable_id, :bigint, null: false
|
122
|
-
t.column :taggable_type, :
|
117
|
+
t.column :taggable_type, :string, null: false
|
123
118
|
|
124
119
|
t.index %i[taggable_id taggable_type tag_id],
|
125
120
|
name: 'motor_polymorphic_association_tag_index',
|
126
|
-
unique: true
|
127
|
-
length: { taggable_type: 255 }
|
121
|
+
unique: true
|
128
122
|
end
|
129
123
|
|
130
124
|
create_table :motor_audits do |t|
|
131
125
|
t.column :auditable_id, :bigint
|
132
|
-
t.column :auditable_type, :
|
126
|
+
t.column :auditable_type, :string
|
133
127
|
t.column :associated_id, :bigint
|
134
|
-
t.column :associated_type, :
|
128
|
+
t.column :associated_type, :string
|
135
129
|
t.column :user_id, :bigint
|
136
|
-
t.column :user_type, :
|
137
|
-
t.column :username, :
|
138
|
-
t.column :action, :
|
130
|
+
t.column :user_type, :string
|
131
|
+
t.column :username, :string
|
132
|
+
t.column :action, :string
|
139
133
|
t.column :audited_changes, :text
|
140
134
|
t.column :version, :bigint, default: 0
|
141
135
|
t.column :comment, :text
|
142
|
-
t.column :remote_address, :
|
143
|
-
t.column :request_uuid, :
|
136
|
+
t.column :remote_address, :string
|
137
|
+
t.column :request_uuid, :string
|
144
138
|
t.column :created_at, :datetime
|
145
139
|
end
|
146
140
|
|
147
|
-
add_index :motor_audits, %i[auditable_type auditable_id version], name: 'motor_auditable_index'
|
148
|
-
|
149
|
-
add_index :motor_audits, %i[
|
150
|
-
|
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 }
|
141
|
+
add_index :motor_audits, %i[auditable_type auditable_id version], name: 'motor_auditable_index'
|
142
|
+
add_index :motor_audits, %i[associated_type associated_id], name: 'motor_auditable_associated_index'
|
143
|
+
add_index :motor_audits, %i[user_id user_type], name: 'motor_auditable_user_index'
|
144
|
+
add_index :motor_audits, :request_uuid
|
154
145
|
add_index :motor_audits, :created_at
|
155
146
|
end
|
156
147
|
|
data/lib/motor/admin.rb
CHANGED
@@ -66,12 +66,12 @@ module Motor
|
|
66
66
|
end
|
67
67
|
|
68
68
|
initializer 'motor.active_storage.extensions' do
|
69
|
-
|
70
|
-
|
71
|
-
ActiveStorage::Engine.eager_load!
|
69
|
+
config.after_initialize do
|
70
|
+
next unless defined?(ActiveStorage::Engine)
|
72
71
|
|
73
|
-
|
74
|
-
|
72
|
+
ActiveStorage::Attachment.include(Motor::ActiveRecordUtils::ActiveStorageLinksExtension)
|
73
|
+
ActiveStorage::Blob.singleton_class.prepend(Motor::ActiveRecordUtils::ActiveStorageBlobPatch)
|
74
|
+
end
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
data/lib/motor/assets.rb
CHANGED
@@ -5,19 +5,24 @@ module Motor
|
|
5
5
|
module RunQuery
|
6
6
|
DEFAULT_LIMIT = 100_000
|
7
7
|
|
8
|
-
QueryResult = Struct.new(:data, :columns, keyword_init: true)
|
8
|
+
QueryResult = Struct.new(:data, :columns, :error, keyword_init: true)
|
9
|
+
|
10
|
+
WITH_STATEMENT_START = 'WITH __query__ AS ('
|
9
11
|
|
10
12
|
WITH_STATEMENT_TEMPLATE = <<~SQL
|
11
|
-
|
13
|
+
#{WITH_STATEMENT_START}%<sql_body>s
|
14
|
+
) SELECT * FROM __query__ LIMIT %<limit>s;
|
12
15
|
SQL
|
13
16
|
|
17
|
+
PG_ERROR_REGEXP = /\APG.+ERROR:/.freeze
|
18
|
+
|
14
19
|
module_function
|
15
20
|
|
16
21
|
# @param query [Motor::Query]
|
17
22
|
# @param variables_hash [Hash]
|
18
23
|
# @param limit [Integer]
|
19
24
|
# @return [Motor::Queries::RunQuery::QueryResult]
|
20
|
-
def call(query, variables_hash: nil, limit: DEFAULT_LIMIT)
|
25
|
+
def call!(query, variables_hash: nil, limit: DEFAULT_LIMIT)
|
21
26
|
variables_hash ||= {}
|
22
27
|
|
23
28
|
result = execute_query(query, limit, variables_hash)
|
@@ -25,6 +30,22 @@ module Motor
|
|
25
30
|
QueryResult.new(data: result.rows, columns: build_columns_hash(result))
|
26
31
|
end
|
27
32
|
|
33
|
+
# @param query [Motor::Query]
|
34
|
+
# @param variables_hash [Hash]
|
35
|
+
# @param limit [Integer]
|
36
|
+
# @return [Motor::Queries::RunQuery::QueryResult]
|
37
|
+
def call(query, variables_hash: nil, limit: DEFAULT_LIMIT)
|
38
|
+
call!(query, variables_hash: variables_hash, limit: limit)
|
39
|
+
rescue ActiveRecord::StatementInvalid => e
|
40
|
+
QueryResult.new(error: build_error_message(e))
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param exception [ActiveRecord::StatementInvalid]
|
44
|
+
# @return [String]
|
45
|
+
def build_error_message(exception)
|
46
|
+
exception.message.sub(WITH_STATEMENT_START, '').sub(PG_ERROR_REGEXP, '').strip.upcase_first
|
47
|
+
end
|
48
|
+
|
28
49
|
# @param query [Motor::Query]
|
29
50
|
# @param limit [Integer]
|
30
51
|
# @param variables_hash [Hash]
|
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-67fbb3a8f6a6388434c8.css.gz": "main-67fbb3a8f6a6388434c8.css.gz",
|
2072
|
+
"main-67fbb3a8f6a6388434c8.js.LICENSE.txt": "main-67fbb3a8f6a6388434c8.js.LICENSE.txt",
|
2073
|
+
"main-67fbb3a8f6a6388434c8.js.gz": "main-67fbb3a8f6a6388434c8.js.gz",
|
2074
|
+
"main.css": "main-67fbb3a8f6a6388434c8.css",
|
2075
|
+
"main.js": "main-67fbb3a8f6a6388434c8.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.53
|
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-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord-filter
|
@@ -108,7 +108,10 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '5.2'
|
111
|
-
description:
|
111
|
+
description: |
|
112
|
+
Motor Admin allows to create a flexible admin panel with writing less code.
|
113
|
+
All customizations to the admin panel can be made directly in the UI without
|
114
|
+
the need of writing any configurations code.
|
112
115
|
email:
|
113
116
|
- pete.matsy@gmail.com
|
114
117
|
executables: []
|
@@ -1481,8 +1484,8 @@ files:
|
|
1481
1484
|
- ui/dist/icons/zoom-money.svg.gz
|
1482
1485
|
- ui/dist/icons/zoom-out.svg.gz
|
1483
1486
|
- ui/dist/icons/zoom-question.svg.gz
|
1484
|
-
- ui/dist/main-
|
1485
|
-
- ui/dist/main-
|
1487
|
+
- ui/dist/main-67fbb3a8f6a6388434c8.css.gz
|
1488
|
+
- ui/dist/main-67fbb3a8f6a6388434c8.js.gz
|
1486
1489
|
- ui/dist/manifest.json
|
1487
1490
|
homepage:
|
1488
1491
|
licenses:
|
@@ -1506,5 +1509,5 @@ requirements: []
|
|
1506
1509
|
rubygems_version: 3.2.3
|
1507
1510
|
signing_key:
|
1508
1511
|
specification_version: 4
|
1509
|
-
summary: Admin
|
1512
|
+
summary: Low-code Admin panel and Business intelligence
|
1510
1513
|
test_files: []
|
Binary file
|
Binary file
|