marty 2.1.5 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +4 -4
- data/app/components/marty/auth_app.rb +3 -3
- data/app/components/marty/auth_app/client/auth_app.js +1 -3
- data/app/components/marty/base_rule_view.rb +32 -20
- data/app/components/marty/data_grid_view.rb +3 -3
- data/app/components/marty/event_view.rb +0 -5
- data/app/components/marty/form.rb +8 -1
- data/app/components/marty/form/client/form.css +3 -0
- data/app/components/marty/grid.rb +174 -33
- data/app/components/marty/import_view.rb +151 -0
- data/app/components/marty/main_auth_app.rb +28 -28
- data/app/components/marty/mcfly_grid_panel.rb +1 -1
- data/app/components/marty/new_posting_form.rb +3 -3
- data/app/components/marty/new_posting_window.rb +5 -6
- data/app/components/marty/posting_grid.rb +2 -2
- data/app/components/marty/posting_window.rb +1 -2
- data/app/components/marty/promise_view.rb +11 -6
- data/app/components/marty/record_form_window.rb +1 -1
- data/app/components/marty/report_form.rb +4 -4
- data/app/components/marty/report_select.rb +1 -1
- data/app/components/marty/script_form.rb +4 -4
- data/app/components/marty/script_grid.rb +2 -2
- data/app/components/marty/script_tester.rb +1 -1
- data/app/components/marty/simple_app.rb +1 -2
- data/app/components/marty/simple_app/client/statusbar_ext.js +1 -1
- data/app/components/marty/tag_grid.rb +1 -1
- data/app/components/marty/user_view.rb +5 -5
- data/app/controllers/marty/job_controller.rb +5 -1
- data/app/models/marty/base.rb +0 -15
- data/app/models/marty/data_grid.rb +1 -1
- data/app/models/marty/log.rb +1 -0
- data/app/models/marty/promise.rb +27 -84
- data/app/models/marty/vw_promise.rb +72 -0
- data/app/views/layouts/marty/application.html.erb +6 -3
- data/config/locales/en.yml +4 -0
- data/db/migrate/410_jsonb_promise_result.rb +9 -0
- data/db/migrate/411_create_vw_promises.rb +26 -0
- data/lib/marty/data_change.rb +3 -4
- data/lib/marty/data_conversion.rb +1 -2
- data/lib/marty/data_importer.rb +13 -14
- data/lib/marty/javascript/{overrides.js → grid_view_in_form.js} +10 -6
- data/lib/marty/mcfly_model.rb +13 -20
- data/lib/marty/monkey.rb +33 -40
- data/lib/marty/promise_job.rb +8 -2
- data/lib/marty/promise_proxy.rb +6 -11
- data/lib/marty/rule_script_set.rb +5 -2
- data/lib/marty/version.rb +1 -1
- data/marty.gemspec +1 -1
- data/other/marty/diagnostic/delayed_job_workers.rb +8 -5
- data/spec/controllers/job_controller_spec.rb +34 -15
- data/spec/dummy/app/components/gemini/my_rule_view.rb +6 -0
- data/spec/dummy/app/models/gemini/helper.rb +2 -2
- data/spec/dummy/config/application.rb +1 -1
- data/spec/features/rule_spec.rb +100 -5
- data/spec/fixtures/csv/rule/MyRule.csv +1 -1
- data/spec/job_helper.rb +2 -4
- data/spec/lib/data_importer_spec.rb +10 -10
- data/spec/lib/delorean_query_spec.rb +13 -2
- data/spec/lib/logger_spec.rb +16 -14
- data/spec/models/data_grid_spec.rb +4 -10
- data/spec/models/promise_spec.rb +8 -8
- data/spec/models/rule_spec.rb +7 -7
- data/spec/spec_helper.rb +1 -1
- metadata +10 -5
@@ -4,6 +4,7 @@ class Marty::PromiseView < Netzke::Tree::Base
|
|
4
4
|
client_styles do |config|
|
5
5
|
config.require :promise_view
|
6
6
|
end
|
7
|
+
|
7
8
|
client_class do |config|
|
8
9
|
config.default_get_row_class = l(<<-JS)
|
9
10
|
function(record, index, rowParams, ds) {
|
@@ -41,7 +42,7 @@ class Marty::PromiseView < Netzke::Tree::Base
|
|
41
42
|
def configure(config)
|
42
43
|
super
|
43
44
|
config.title = I18n.t("jobs.promise_view")
|
44
|
-
config.model = "Marty::
|
45
|
+
config.model = "Marty::VwPromise"
|
45
46
|
config.attributes = [
|
46
47
|
{name: :title, xtype: :treecolumn},
|
47
48
|
:user__login,
|
@@ -114,20 +115,20 @@ class Marty::PromiseView < Netzke::Tree::Base
|
|
114
115
|
action :clear do |a|
|
115
116
|
a.text = a.tooltip = 'Clear'
|
116
117
|
a.disabled = false
|
117
|
-
a.
|
118
|
+
a.icon_cls = "fa fa-minus glyph"
|
118
119
|
a.hidden = !self.class.has_admin_perm?
|
119
120
|
end
|
120
121
|
|
121
122
|
action :download do |a|
|
122
123
|
a.text = a.tooltip = 'Download'
|
123
124
|
a.disabled = true
|
124
|
-
a.
|
125
|
+
a.icon_cls = "fa fa-download glyph"
|
125
126
|
end
|
126
127
|
|
127
128
|
action :refresh do |a|
|
128
129
|
a.text = a.tooltip = 'Refresh'
|
129
130
|
a.disabled = false
|
130
|
-
a.
|
131
|
+
a.icon_cls = "fa fa-sync-alt glyph"
|
131
132
|
end
|
132
133
|
|
133
134
|
endpoint :clear do |params|
|
@@ -137,7 +138,7 @@ class Marty::PromiseView < Netzke::Tree::Base
|
|
137
138
|
|
138
139
|
def get_records params
|
139
140
|
search_scope = config[:live_search_scope] || :live_search
|
140
|
-
Marty::
|
141
|
+
Marty::VwPromise.children_for_id(params[:id], params[search_scope])
|
141
142
|
end
|
142
143
|
|
143
144
|
attribute :title do |config|
|
@@ -172,7 +173,11 @@ class Marty::PromiseView < Netzke::Tree::Base
|
|
172
173
|
end
|
173
174
|
|
174
175
|
attribute :error do |config|
|
175
|
-
config.getter = ->(record) {
|
176
|
+
config.getter = ->(record) {
|
177
|
+
if !record.status
|
178
|
+
Marty::Promise.find_by(id: record.id).try(:result).to_s
|
179
|
+
end
|
180
|
+
}
|
176
181
|
config.flex = 1
|
177
182
|
end
|
178
183
|
end
|
@@ -4,19 +4,19 @@ class Marty::ReportForm < Marty::Form
|
|
4
4
|
action :apply do |a|
|
5
5
|
a.text = a.tooltip = I18n.t("reporting.background")
|
6
6
|
a.handler = :netzke_on_apply
|
7
|
-
a.
|
7
|
+
a.icon_cls = "fa fa-cloud glyph"
|
8
8
|
a.disabled = false
|
9
9
|
end
|
10
10
|
|
11
11
|
action :foreground do |a|
|
12
12
|
a.text = a.tooltip = I18n.t("reporting.generate")
|
13
|
-
a.
|
13
|
+
a.icon_cls = "fa fa-download glyph"
|
14
14
|
a.disabled = false
|
15
15
|
end
|
16
16
|
|
17
17
|
action :link do |a|
|
18
18
|
a.text = a.tooltip = I18n.t("reporting.link")
|
19
|
-
a.
|
19
|
+
a.icon_cls = "fa fa-link glyph"
|
20
20
|
a.disabled = false
|
21
21
|
end
|
22
22
|
|
@@ -262,7 +262,7 @@ class Marty::ReportForm < Marty::Form
|
|
262
262
|
}
|
263
263
|
}
|
264
264
|
|
265
|
-
c.items = items
|
265
|
+
c.items = add_cls_to_fields(items)
|
266
266
|
c.repformat = format
|
267
267
|
c.title = "Generate: #{title}-#{sset.tag.name}"
|
268
268
|
c.reptitle = title
|
@@ -109,7 +109,7 @@ class Marty::ScriptForm < Marty::Form
|
|
109
109
|
action :apply do |a|
|
110
110
|
a.text = I18n.t("script_form.save")
|
111
111
|
a.tooltip = I18n.t("script_form.save")
|
112
|
-
a.
|
112
|
+
a.icon_cls = "fa fa-save glyph"
|
113
113
|
a.disabled = true
|
114
114
|
end
|
115
115
|
|
@@ -191,9 +191,9 @@ class Marty::ScriptForm < Marty::Form
|
|
191
191
|
######################################################################
|
192
192
|
|
193
193
|
action :do_print do |a|
|
194
|
-
a.text
|
195
|
-
a.tooltip
|
196
|
-
a.
|
194
|
+
a.text = I18n.t("script_form.print")
|
195
|
+
a.tooltip = I18n.t("script_form.print")
|
196
|
+
a.icon_cls = "fa fa-print glyph"
|
197
197
|
end
|
198
198
|
|
199
199
|
######################################################################
|
@@ -34,7 +34,7 @@ class Marty::ScriptGrid < Marty::Grid
|
|
34
34
|
action :delete do |a|
|
35
35
|
a.text = I18n.t("script_grid.delete")
|
36
36
|
a.tooltip = I18n.t("script_grid.delete")
|
37
|
-
a.
|
37
|
+
a.icon_cls = "fa fa-trash glyph"
|
38
38
|
a.disabled = config[:prohibit_delete]
|
39
39
|
end
|
40
40
|
|
@@ -77,7 +77,7 @@ class Marty::ScriptGrid < Marty::Grid
|
|
77
77
|
action :add_in_form do |a|
|
78
78
|
a.text = I18n.t("script_grid.new")
|
79
79
|
a.tooltip = I18n.t("script_grid.new")
|
80
|
-
a.
|
80
|
+
a.icon_cls = "fa fa-plus glyph"
|
81
81
|
a.disabled = !config[:permissions][:create]
|
82
82
|
end
|
83
83
|
|
@@ -66,7 +66,6 @@ class Marty::SimpleApp < Netzke::Base
|
|
66
66
|
:itemId => 'status_bar',
|
67
67
|
:xtype => 'statusbar',
|
68
68
|
:region => 'south',
|
69
|
-
:height => 22,
|
70
69
|
:statusAlign => 'right',
|
71
70
|
:busyText => 'Busy...',
|
72
71
|
:default_text => "Ready",
|
@@ -78,9 +77,9 @@ class Marty::SimpleApp < Netzke::Base
|
|
78
77
|
def menu_bar_config(overrides = {})
|
79
78
|
{
|
80
79
|
:itemId => 'menu_bar',
|
80
|
+
:layout => {overflow_handler: 'Menu'},
|
81
81
|
:xtype => 'toolbar',
|
82
82
|
:region => 'north',
|
83
|
-
:height => 28,
|
84
83
|
:items => menu
|
85
84
|
}.merge(overrides)
|
86
85
|
end
|
@@ -100,19 +100,19 @@ module Marty; class UserView < Marty::Grid
|
|
100
100
|
|
101
101
|
action :add do |a|
|
102
102
|
super(a)
|
103
|
-
a.text
|
104
|
-
a.tooltip
|
105
|
-
a.
|
103
|
+
a.text = I18n.t("user_grid.new")
|
104
|
+
a.tooltip = I18n.t("user_grid.new")
|
105
|
+
a.icon_cls = "fa fa-user-plus glyph"
|
106
106
|
end
|
107
107
|
|
108
108
|
action :edit do |a|
|
109
109
|
super(a)
|
110
|
-
a.
|
110
|
+
a.icon_cls = "fa fa-user-cog glyph"
|
111
111
|
end
|
112
112
|
|
113
113
|
action :delete do |a|
|
114
114
|
super(a)
|
115
|
-
a.
|
115
|
+
a.icon_cls = "fa fa-user-minus glyph"
|
116
116
|
end
|
117
117
|
|
118
118
|
def default_context_menu
|
@@ -6,9 +6,13 @@ class Marty::JobController < ActionController::Base
|
|
6
6
|
|
7
7
|
if promise
|
8
8
|
format = promise.cformat
|
9
|
+
|
10
|
+
# Force result so finalized object is built
|
11
|
+
data = promise.result(true)
|
12
|
+
|
9
13
|
# somewhat hacky: if result has "result" key, it's used as the
|
10
14
|
# content.
|
11
|
-
data =
|
15
|
+
data = data["result"] || data
|
12
16
|
title = promise.title
|
13
17
|
else
|
14
18
|
format = "json"
|
data/app/models/marty/base.rb
CHANGED
@@ -6,21 +6,6 @@ class Marty::Base < ActiveRecord::Base
|
|
6
6
|
tb = self.table_name
|
7
7
|
self.where("#{tb}.obsoleted_dt >= ? AND #{tb}.created_dt < ?", pt, pt)
|
8
8
|
end
|
9
|
-
MCFLY_PT_SIG = [1, 1]
|
10
|
-
|
11
|
-
# FIXME: hacky signatures for AR queries
|
12
|
-
COUNT_SIG = [0, 0]
|
13
|
-
DISTINCT_SIG = [0, 100]
|
14
|
-
FIRST_SIG = [0, 1]
|
15
|
-
GROUP_SIG = [1, 100]
|
16
|
-
JOINS_SIG = [1, 100]
|
17
|
-
LAST_SIG = [0, 1]
|
18
|
-
LIMIT_SIG = [1, 1]
|
19
|
-
NOT_SIG = [1, 100]
|
20
|
-
ORDER_SIG = [1, 100]
|
21
|
-
PLUCK_SIG = [1, 100]
|
22
|
-
SELECT_SIG = [1, 100]
|
23
|
-
WHERE_SIG = [0, 100]
|
24
9
|
|
25
10
|
class << self
|
26
11
|
attr_accessor :struct_attrs
|
@@ -188,7 +188,7 @@ class Marty::DataGrid < Marty::Base
|
|
188
188
|
h = dgh["metadata"].each_with_object({}) do |m, h|
|
189
189
|
attr = m["attr"]
|
190
190
|
inc = h_passed.fetch(attr, :__nf__)
|
191
|
-
next if inc == :__nf__
|
191
|
+
next if inc == :__nf__ || inc.nil?
|
192
192
|
val = (defined? inc.name) ? inc.name : inc
|
193
193
|
h[attr] = val.is_a?(String) ?
|
194
194
|
ActiveRecord::Base.connection.quote(val)[1..-2] : val
|
data/app/models/marty/log.rb
CHANGED
data/app/models/marty/promise.rb
CHANGED
@@ -1,14 +1,4 @@
|
|
1
1
|
class Marty::Promise < Marty::Base
|
2
|
-
class MarshalResult
|
3
|
-
def dump(v)
|
4
|
-
Marshal.dump(v)
|
5
|
-
end
|
6
|
-
|
7
|
-
def load(v)
|
8
|
-
# Marshal.load can't handle nil
|
9
|
-
v ? Marshal.load(v) : {}
|
10
|
-
end
|
11
|
-
end
|
12
2
|
|
13
3
|
# default timeout (seconds) to wait for promise values
|
14
4
|
DEFAULT_PROMISE_TIMEOUT = Rails.configuration.marty.promise_timeout || 30
|
@@ -16,30 +6,38 @@ class Marty::Promise < Marty::Base
|
|
16
6
|
# default timeout (seconds) to wait for jobs to start
|
17
7
|
DEFAULT_JOB_TIMEOUT = Rails.configuration.marty.job_timeout || 10
|
18
8
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
}
|
23
|
-
def result
|
24
|
-
unless has_attribute?(:result)
|
25
|
-
changes_before_reload = self.changes.clone
|
26
|
-
self.reload
|
27
|
-
changes_before_reload.each{
|
28
|
-
|attribute_name, values|
|
29
|
-
self.send("#{attribute_name}=", values[1])
|
30
|
-
}
|
31
|
-
end
|
32
|
-
read_attribute :result
|
9
|
+
def result(force=false)
|
10
|
+
res = super()
|
11
|
+
Marty::Promise.load_result(res, force)
|
33
12
|
end
|
34
13
|
|
35
|
-
|
14
|
+
def self.load_result(obj, force=false)
|
15
|
+
if force && obj.respond_to?(:__force__)
|
16
|
+
obj = obj.__force__
|
17
|
+
end
|
18
|
+
|
19
|
+
case obj
|
20
|
+
when Array
|
21
|
+
obj.map {|x| load_result(x, force)}
|
22
|
+
when Hash
|
23
|
+
p = obj['__promise__']
|
36
24
|
|
37
|
-
|
25
|
+
if p && obj.length==1
|
26
|
+
load_result(Marty::PromiseProxy.new(*p), force)
|
27
|
+
else
|
28
|
+
obj.each_with_object({}) { |(k, v), h| h[k] = load_result(v, force) }
|
29
|
+
end
|
30
|
+
else
|
31
|
+
obj
|
32
|
+
end
|
33
|
+
end
|
38
34
|
|
39
35
|
has_many :children,
|
40
|
-
|
41
|
-
|
42
|
-
|
36
|
+
foreign_key: 'parent_id',
|
37
|
+
class_name: "Marty::Promise",
|
38
|
+
dependent: :destroy
|
39
|
+
|
40
|
+
validates_presence_of :title
|
43
41
|
|
44
42
|
belongs_to :parent, class_name: "Marty::Promise"
|
45
43
|
belongs_to :user, class_name: "Marty::User"
|
@@ -53,43 +51,6 @@ class Marty::Promise < Marty::Base
|
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
56
|
-
class VirtualRoot
|
57
|
-
def self.primary_key
|
58
|
-
'id'
|
59
|
-
end
|
60
|
-
|
61
|
-
def id
|
62
|
-
'root'
|
63
|
-
end
|
64
|
-
|
65
|
-
def user_id
|
66
|
-
0
|
67
|
-
end
|
68
|
-
alias_method :job_id, :user_id
|
69
|
-
|
70
|
-
def result
|
71
|
-
nil
|
72
|
-
end
|
73
|
-
[:start_dt, :end_dt].each { |m| alias_method m, :result }
|
74
|
-
|
75
|
-
def status
|
76
|
-
true
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.root
|
81
|
-
VirtualRoot.new
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.children_for_id(id, search_order)
|
85
|
-
q = id == 'root' ? where(parent_id: nil) : find(id).children
|
86
|
-
q.live_search(search_order).order(id: :desc).includes(:children, :user)
|
87
|
-
end
|
88
|
-
|
89
|
-
def leaf
|
90
|
-
children.empty?
|
91
|
-
end
|
92
|
-
|
93
54
|
def raw_conn
|
94
55
|
self.class.connection.raw_connection
|
95
56
|
end
|
@@ -242,22 +203,4 @@ class Marty::Promise < Marty::Base
|
|
242
203
|
raw_conn.exec("UNLISTEN promise_#{id}")
|
243
204
|
end
|
244
205
|
end
|
245
|
-
|
246
|
-
# Support UI live search -- FIXME: hacky to have UI scoping here
|
247
|
-
scope :live_search, lambda { |search_text|
|
248
|
-
return if !search_text || search_text.strip.length < 1
|
249
|
-
|
250
|
-
# Searches user login/firstname/lastname
|
251
|
-
query = [
|
252
|
-
"marty_users.login ILIKE ?",
|
253
|
-
"marty_users.firstname ILIKE ?",
|
254
|
-
"marty_users.lastname ILIKE ?",
|
255
|
-
"marty_roles.name ILIKE ?",
|
256
|
-
].join(' OR ')
|
257
|
-
|
258
|
-
st = "%#{search_text}%"
|
259
|
-
# Convert "Role Name" or "Role name" to "role_name" (underscore is key)
|
260
|
-
st2 = "%#{search_text.titleize.gsub(/\s/, '').underscore}%"
|
261
|
-
joins({:user => :roles}).where(query, st, st, st, st2).distinct
|
262
|
-
}
|
263
206
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Marty::VwPromise < Marty::Base
|
2
|
+
|
3
|
+
has_many :children,
|
4
|
+
foreign_key: 'parent_id',
|
5
|
+
class_name: "Marty::VwPromise",
|
6
|
+
dependent: :destroy
|
7
|
+
|
8
|
+
belongs_to :parent, class_name: "Marty::VwPromise"
|
9
|
+
belongs_to :user, class_name: "Marty::User"
|
10
|
+
|
11
|
+
self.table_name = 'marty_vw_promises'
|
12
|
+
self.primary_key = 'id'
|
13
|
+
|
14
|
+
class VirtualRoot
|
15
|
+
def self.primary_key
|
16
|
+
'id'
|
17
|
+
end
|
18
|
+
|
19
|
+
def id
|
20
|
+
'root'
|
21
|
+
end
|
22
|
+
|
23
|
+
def user_id
|
24
|
+
0
|
25
|
+
end
|
26
|
+
alias_method :job_id, :user_id
|
27
|
+
|
28
|
+
def result
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
[:start_dt, :end_dt].each { |m| alias_method m, :result }
|
32
|
+
|
33
|
+
def status
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.root
|
39
|
+
VirtualRoot.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.children_for_id(id, search_order)
|
43
|
+
q = id == 'root' ? where(parent_id: nil) : find(id).children
|
44
|
+
q.live_search(search_order).order(id: :desc).includes(:children, :user)
|
45
|
+
end
|
46
|
+
|
47
|
+
def leaf
|
48
|
+
children.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
inspect
|
53
|
+
end
|
54
|
+
|
55
|
+
# Support UI live search -- FIXME: hacky to have UI scoping here
|
56
|
+
scope :live_search, lambda { |search_text|
|
57
|
+
return if !search_text || search_text.strip.length < 1
|
58
|
+
|
59
|
+
# Searches user login/firstname/lastname
|
60
|
+
query = [
|
61
|
+
"marty_users.login ILIKE ?",
|
62
|
+
"marty_users.firstname ILIKE ?",
|
63
|
+
"marty_users.lastname ILIKE ?",
|
64
|
+
"marty_roles.name ILIKE ?",
|
65
|
+
].join(' OR ')
|
66
|
+
|
67
|
+
st = "%#{search_text}%"
|
68
|
+
# Convert "Role Name" or "Role name" to "role_name" (underscore is key)
|
69
|
+
st2 = "%#{search_text.titleize.gsub(/\s/, '').underscore}%"
|
70
|
+
joins({:user => :roles}).where(query, st, st, st, st2).distinct
|
71
|
+
}
|
72
|
+
end
|