marty 2.1.5 → 2.3.0

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +4 -4
  4. data/app/components/marty/auth_app.rb +3 -3
  5. data/app/components/marty/auth_app/client/auth_app.js +1 -3
  6. data/app/components/marty/base_rule_view.rb +32 -20
  7. data/app/components/marty/data_grid_view.rb +3 -3
  8. data/app/components/marty/event_view.rb +0 -5
  9. data/app/components/marty/form.rb +8 -1
  10. data/app/components/marty/form/client/form.css +3 -0
  11. data/app/components/marty/grid.rb +174 -33
  12. data/app/components/marty/import_view.rb +151 -0
  13. data/app/components/marty/main_auth_app.rb +28 -28
  14. data/app/components/marty/mcfly_grid_panel.rb +1 -1
  15. data/app/components/marty/new_posting_form.rb +3 -3
  16. data/app/components/marty/new_posting_window.rb +5 -6
  17. data/app/components/marty/posting_grid.rb +2 -2
  18. data/app/components/marty/posting_window.rb +1 -2
  19. data/app/components/marty/promise_view.rb +11 -6
  20. data/app/components/marty/record_form_window.rb +1 -1
  21. data/app/components/marty/report_form.rb +4 -4
  22. data/app/components/marty/report_select.rb +1 -1
  23. data/app/components/marty/script_form.rb +4 -4
  24. data/app/components/marty/script_grid.rb +2 -2
  25. data/app/components/marty/script_tester.rb +1 -1
  26. data/app/components/marty/simple_app.rb +1 -2
  27. data/app/components/marty/simple_app/client/statusbar_ext.js +1 -1
  28. data/app/components/marty/tag_grid.rb +1 -1
  29. data/app/components/marty/user_view.rb +5 -5
  30. data/app/controllers/marty/job_controller.rb +5 -1
  31. data/app/models/marty/base.rb +0 -15
  32. data/app/models/marty/data_grid.rb +1 -1
  33. data/app/models/marty/log.rb +1 -0
  34. data/app/models/marty/promise.rb +27 -84
  35. data/app/models/marty/vw_promise.rb +72 -0
  36. data/app/views/layouts/marty/application.html.erb +6 -3
  37. data/config/locales/en.yml +4 -0
  38. data/db/migrate/410_jsonb_promise_result.rb +9 -0
  39. data/db/migrate/411_create_vw_promises.rb +26 -0
  40. data/lib/marty/data_change.rb +3 -4
  41. data/lib/marty/data_conversion.rb +1 -2
  42. data/lib/marty/data_importer.rb +13 -14
  43. data/lib/marty/javascript/{overrides.js → grid_view_in_form.js} +10 -6
  44. data/lib/marty/mcfly_model.rb +13 -20
  45. data/lib/marty/monkey.rb +33 -40
  46. data/lib/marty/promise_job.rb +8 -2
  47. data/lib/marty/promise_proxy.rb +6 -11
  48. data/lib/marty/rule_script_set.rb +5 -2
  49. data/lib/marty/version.rb +1 -1
  50. data/marty.gemspec +1 -1
  51. data/other/marty/diagnostic/delayed_job_workers.rb +8 -5
  52. data/spec/controllers/job_controller_spec.rb +34 -15
  53. data/spec/dummy/app/components/gemini/my_rule_view.rb +6 -0
  54. data/spec/dummy/app/models/gemini/helper.rb +2 -2
  55. data/spec/dummy/config/application.rb +1 -1
  56. data/spec/features/rule_spec.rb +100 -5
  57. data/spec/fixtures/csv/rule/MyRule.csv +1 -1
  58. data/spec/job_helper.rb +2 -4
  59. data/spec/lib/data_importer_spec.rb +10 -10
  60. data/spec/lib/delorean_query_spec.rb +13 -2
  61. data/spec/lib/logger_spec.rb +16 -14
  62. data/spec/models/data_grid_spec.rb +4 -10
  63. data/spec/models/promise_spec.rb +8 -8
  64. data/spec/models/rule_spec.rb +7 -7
  65. data/spec/spec_helper.rb +1 -1
  66. 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::Promise"
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.icon = :application_delete
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.icon = :application_put
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.icon = :arrow_refresh
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::Promise.children_for_id(params[:id], params[search_scope])
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) { record.result.to_s if record.status == false }
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
@@ -1,7 +1,7 @@
1
1
  class Marty::RecordFormWindow < Netzke::Basepack::RecordFormWindow
2
2
  def configure(c)
3
3
  super c
4
- c.fbar = [] if c.item_id == 'view_window'
4
+ c.fbar = nil if c.item_id == 'view_window'
5
5
  end
6
6
 
7
7
  component :view_form do |c|
@@ -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.icon = :report_disk
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.icon = :report_go
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.icon = :link_go
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
@@ -42,7 +42,7 @@ class Marty::ReportSelect < Marty::Form
42
42
  {},
43
43
  ),
44
44
  ]
45
- c.bbar = []
45
+ c.bbar = nil
46
46
  end
47
47
 
48
48
  client_class do |c|
@@ -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.icon = :database_save
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 = I18n.t("script_form.print")
195
- a.tooltip = I18n.t("script_form.print")
196
- a.icon = :printer
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.icon = :script_delete
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.icon = :script_add
80
+ a.icon_cls = "fa fa-plus glyph"
81
81
  a.disabled = !config[:permissions][:create]
82
82
  end
83
83
 
@@ -96,7 +96,7 @@ class Marty::ScriptTester < Marty::Form
96
96
  action :apply do |a|
97
97
  a.text = I18n.t("script_tester.compute")
98
98
  a.tooltip = I18n.t("script_tester.compute")
99
- a.icon = :script_go
99
+ a.icon_cls = "fa fa-bug glyph"
100
100
  a.disabled = false
101
101
  end
102
102
 
@@ -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
@@ -2,7 +2,7 @@ Ext.override(Ext.ux.StatusBar, {
2
2
  hideBusy : function(){
3
3
  return this.setStatus({
4
4
  text: this.defaultText,
5
- iconCls: this.defaultIconCls
5
+ icon_cls: this.defaultIconCls
6
6
  });
7
7
  }
8
8
  });
@@ -38,7 +38,7 @@ class Marty::TagGrid < Marty::Grid
38
38
  action :add_in_form do |a|
39
39
  a.text = I18n.t("tag_grid.new")
40
40
  a.tooltip = I18n.t("tag_grid.new")
41
- a.icon = :time_add
41
+ a.icon_cls = "fa fa-clock glyph"
42
42
  a.disabled = !config[:permissions][:create]
43
43
  end
44
44
 
@@ -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 = I18n.t("user_grid.new")
104
- a.tooltip = I18n.t("user_grid.new")
105
- a.icon = :user_add
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.icon = :user_edit
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.icon = :user_delete
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 = promise.result["result"] || promise.result
15
+ data = data["result"] || data
12
16
  title = promise.title
13
17
  else
14
18
  format = "json"
@@ -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
@@ -12,6 +12,7 @@ class Marty::Log < Marty::Base
12
12
  rescue => e
13
13
  Marty::Util.logger.error("Marty::Logger failure: #{e.message}")
14
14
  end
15
+ true
15
16
  end
16
17
 
17
18
  def self.cleanup(days_to_keep)
@@ -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
- SELECT_COLS = columns.map(&:name)-["result"]
20
- default_scope {
21
- select(*SELECT_COLS)
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
- serialize :result, MarshalResult.new
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
- validates_presence_of :title
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
- foreign_key: 'parent_id',
41
- class_name: "Marty::Promise",
42
- dependent: :destroy
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