marty 1.2.0 → 1.2.1
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/Gemfile +2 -1
- data/Gemfile.lock +2 -2
- data/app/components/marty/base_rule_view.rb +279 -0
- data/app/components/marty/delorean_rule_view.rb +26 -0
- data/app/components/marty/extras/layout.rb +22 -7
- data/app/components/marty/log_view.rb +1 -1
- data/app/components/marty/mcfly_grid_panel.rb +53 -0
- data/app/components/marty/mcfly_grid_panel/client/dup_in_form.js +20 -0
- data/app/models/marty/base_rule.rb +126 -0
- data/app/models/marty/delorean_rule.rb +121 -0
- data/lib/marty/data_importer.rb +0 -1
- data/lib/marty/rule_script_set.rb +176 -0
- data/lib/marty/version.rb +1 -1
- data/lib/tasks/marty_tasks.rake +42 -0
- data/spec/dummy/app/components/gemini/cm_auth_app.rb +18 -0
- data/spec/dummy/app/components/gemini/my_rule_view.rb +63 -0
- data/spec/dummy/app/components/gemini/xyz_rule_view.rb +25 -0
- data/spec/dummy/app/models/gemini/guard_one.rb +5 -0
- data/spec/dummy/app/models/gemini/guard_two.rb +5 -0
- data/spec/dummy/app/models/gemini/my_rule.rb +46 -0
- data/spec/dummy/app/models/gemini/my_rule_type.rb +5 -0
- data/spec/dummy/app/models/gemini/xyz_enum.rb +5 -0
- data/spec/dummy/app/models/gemini/xyz_rule.rb +63 -0
- data/spec/dummy/app/models/gemini/xyz_rule_type.rb +5 -0
- data/spec/dummy/config/locales/en.yml +10 -0
- data/spec/dummy/db/migrate/20171220150101_add_rule_type_enums.rb +14 -0
- data/spec/dummy/db/migrate/20171221095312_create_gemini_my_rules.rb +22 -0
- data/spec/dummy/db/migrate/20171221095359_create_gemini_xyz_rules.rb +21 -0
- data/spec/dummy/db/migrate/20171222150100_add_rule_indices.rb +34 -0
- data/spec/dummy/db/seeds.rb +1 -1
- data/spec/dummy/delorean/base_code.dl +6 -0
- data/spec/dummy/lib/gemini/my_rule_script_set.rb +13 -0
- data/spec/dummy/lib/gemini/xyz_rule_script_set.rb +22 -0
- data/spec/features/rule_spec.rb +265 -0
- data/spec/fixtures/csv/rule/DataGrid.csv +6 -0
- data/spec/fixtures/csv/rule/MyRule.csv +14 -0
- data/spec/fixtures/csv/rule/XyzRule.csv +6 -0
- data/spec/models/rule_spec.rb +322 -0
- data/spec/support/integration_helpers.rb +1 -0
- metadata +29 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f72e47b8af214afae1185098fad62b86cb4c740c
|
4
|
+
data.tar.gz: f23fdf9fb57e514b3d67340abd050b59b7c1b8ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35b2e57e4e67136307490955a47ecdd8ad4a8b45c0d4752492a4b144a9a3764a51c7f7f48fbf844e9ddeb7b92364b3d38d86c30fe3990e60fc27627556ca1612
|
7
|
+
data.tar.gz: bd9300147c167ac3e3934666c8249cf80f2c35e20ec67723d0a70311c6e1cc64e2f20a5bb5ad5931b4ee43876e8cad9d8dcde4f8c1bfbaf7ddc80884c96ec85e
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
marty (1.2.
|
4
|
+
marty (1.2.1)
|
5
5
|
axlsx (= 2.1.0pre)
|
6
6
|
coderay
|
7
7
|
delorean_lang (~> 0.3.33)
|
@@ -83,7 +83,7 @@ GEM
|
|
83
83
|
delayed_job_active_record (4.1.2)
|
84
84
|
activerecord (>= 3.0, < 5.2)
|
85
85
|
delayed_job (>= 3.0, < 5)
|
86
|
-
delorean_lang (0.3.
|
86
|
+
delorean_lang (0.3.33)
|
87
87
|
activerecord (>= 3.2)
|
88
88
|
treetop (~> 1.5)
|
89
89
|
diff-lcs (1.3)
|
@@ -0,0 +1,279 @@
|
|
1
|
+
class Marty::BaseRuleView < Marty::McflyGridPanel
|
2
|
+
include Marty::Extras::Layout
|
3
|
+
|
4
|
+
def self.klass
|
5
|
+
Marty::BaseRule
|
6
|
+
end
|
7
|
+
def klass
|
8
|
+
self.class.klass
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.base_fields
|
12
|
+
[:name]
|
13
|
+
end
|
14
|
+
def self.computed_fields
|
15
|
+
[:computed_guards, :grids, :results]
|
16
|
+
end
|
17
|
+
def configure(c)
|
18
|
+
super
|
19
|
+
c.model = self.class.klass
|
20
|
+
c.title = I18n.t('rule')
|
21
|
+
c.attributes = self.class.base_fields +
|
22
|
+
klass.guard_info.
|
23
|
+
sort_by{|_, h| h[:order] || 0}.
|
24
|
+
reject{|_, h| h[:hidden]}.
|
25
|
+
map { |name, _| name.to_sym } + self.class.computed_fields
|
26
|
+
c.store_config.merge!(sorters: [{property: :name, direction: 'ASC'}])
|
27
|
+
c.editing = :in_form
|
28
|
+
c.paging = :pagination
|
29
|
+
c.multi_select = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def default_bbar
|
33
|
+
super + [:dup_in_form]
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_context_menu
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
|
40
|
+
class DupKeyError < StandardError
|
41
|
+
def initialize(key, lineno)
|
42
|
+
@key = key
|
43
|
+
@lineno = lineno
|
44
|
+
end
|
45
|
+
def message
|
46
|
+
"keyword '#{@key}' specified more than once (line #{@lineno})"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.simple_to_hashstr(s)
|
51
|
+
pairs = []
|
52
|
+
keys = Set.new
|
53
|
+
s.lines.each.with_index(1) do |line, idx|
|
54
|
+
next if /\A\s*\z/.match(line)
|
55
|
+
line.chomp!
|
56
|
+
begin
|
57
|
+
m = /\A\s*([a-z0-9][a-z0-9_]*)\s*=\s*(.*)\s*\z/.match(line)
|
58
|
+
k, v = m[1], m[2]
|
59
|
+
v = [v].to_json[1..-2]
|
60
|
+
raise DupKeyError.new(k, idx) if keys.include?(k)
|
61
|
+
raise unless /\A['"].*['"]\z/.match(v)
|
62
|
+
keys << k
|
63
|
+
rescue DupKeyError => e
|
64
|
+
raise
|
65
|
+
rescue => e
|
66
|
+
raise "syntax error on line #{idx}"
|
67
|
+
end
|
68
|
+
pairs << [k, v]
|
69
|
+
end
|
70
|
+
|
71
|
+
kvs = pairs.map { |k, v| %Q("#{k}":#{v}) }.join(",")
|
72
|
+
"{#{kvs}}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.hash_to_simple(h)
|
76
|
+
return unless h && h.present?
|
77
|
+
fmt = '%-' + h.keys.map(&:length).max.to_s + 's = %s'
|
78
|
+
h.map do |k, vstr|
|
79
|
+
fmt % [k, vstr]
|
80
|
+
end.join("\n") || ''
|
81
|
+
end
|
82
|
+
|
83
|
+
def jsonb_getter(c)
|
84
|
+
lambda { |r| md = r.send(c); md.present? && md.to_json || '' }
|
85
|
+
end
|
86
|
+
|
87
|
+
def jsonb_simple_getter(c)
|
88
|
+
lambda {|r| Marty::BaseRuleView.hash_to_simple(r.send(c)) }
|
89
|
+
end
|
90
|
+
|
91
|
+
def jsonb_simple_setter(c)
|
92
|
+
msg = "#{c}="
|
93
|
+
lambda { |r, v|
|
94
|
+
return r.send(msg, nil) if v.blank?
|
95
|
+
|
96
|
+
begin
|
97
|
+
v = ActiveSupport::JSON.decode(
|
98
|
+
Marty::BaseRuleView.simple_to_hashstr(v))
|
99
|
+
rescue => e
|
100
|
+
v = { "~~ERROR~~": e.message }
|
101
|
+
end
|
102
|
+
r.send(msg, v)
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.jsonb_field_getter(j, c)
|
107
|
+
lambda { |r| r.send(j)[c]||"" }
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.jsonb_field_setter(j, c)
|
111
|
+
lambda do |r, v|
|
112
|
+
v.blank? || v == '---' ? r.send(j).delete(c) : r.send(j)[c] = v
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def json_sort_scope(c)
|
117
|
+
lambda { |r, dir| r.order("#{c}::text " + dir.to_s) }
|
118
|
+
end
|
119
|
+
|
120
|
+
component :add_window do |c|
|
121
|
+
super(c)
|
122
|
+
c.width = 1500
|
123
|
+
c.height = 740
|
124
|
+
end
|
125
|
+
|
126
|
+
component :edit_window do |c|
|
127
|
+
super(c)
|
128
|
+
c.width = 1500
|
129
|
+
c.height = 740
|
130
|
+
end
|
131
|
+
|
132
|
+
attribute :name do |c|
|
133
|
+
c.width = 150
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.grid_column(c, label=nil)
|
137
|
+
editor_config = {
|
138
|
+
trigger_action: :all,
|
139
|
+
xtype: :combo,
|
140
|
+
store: Marty::DataGrid.where(obsoleted_dt: 'infinity').
|
141
|
+
pluck(:name) + ['---'],
|
142
|
+
forceSelection: true,
|
143
|
+
}
|
144
|
+
{
|
145
|
+
name: label || c,
|
146
|
+
width: 200,
|
147
|
+
column_config: { editor: editor_config },
|
148
|
+
field_config: editor_config,
|
149
|
+
type: :string,
|
150
|
+
getter: jsonb_field_getter(:grids, c.to_s),
|
151
|
+
setter: jsonb_field_setter(:grids, c.to_s),
|
152
|
+
# getter: lambda { |r| r.grids[c.to_s] },
|
153
|
+
# setter: lambda { |r, v| r.grids[c.to_s] = v },
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
def form_items_attrs
|
158
|
+
self.class.base_fields
|
159
|
+
end
|
160
|
+
|
161
|
+
def form_items_guards
|
162
|
+
klass.guard_info.reject{|_, h| h[:hidden]}.keys.map{|x|x.to_sym}
|
163
|
+
end
|
164
|
+
|
165
|
+
def form_items_grids
|
166
|
+
[jsonb_field(:grids,
|
167
|
+
getter: jsonb_simple_getter(:grids),
|
168
|
+
setter: jsonb_simple_setter(:grids),
|
169
|
+
height: 75)]
|
170
|
+
end
|
171
|
+
|
172
|
+
def form_items_computed_guards
|
173
|
+
[jsonb_field(:computed_guards,
|
174
|
+
getter: jsonb_simple_getter(:computed_guards),
|
175
|
+
setter: jsonb_simple_setter(:computed_guards),
|
176
|
+
height: 150)]
|
177
|
+
end
|
178
|
+
|
179
|
+
def form_items_results
|
180
|
+
[jsonb_field(:results,
|
181
|
+
getter: jsonb_simple_getter(:results),
|
182
|
+
setter: jsonb_simple_setter(:results),
|
183
|
+
height: 150)]
|
184
|
+
end
|
185
|
+
|
186
|
+
def default_form_items
|
187
|
+
[
|
188
|
+
hbox(
|
189
|
+
vbox(*form_items_attrs +
|
190
|
+
form_items_guards,
|
191
|
+
border: false,
|
192
|
+
width: "40%",
|
193
|
+
),
|
194
|
+
vbox(width: '2%', border: false),
|
195
|
+
vbox(
|
196
|
+
width: '55%', border: false),
|
197
|
+
height: '40%',
|
198
|
+
border: false,
|
199
|
+
),
|
200
|
+
hbox(
|
201
|
+
vbox(*form_items_computed_guards +
|
202
|
+
form_items_grids +
|
203
|
+
form_items_results,
|
204
|
+
width: '99%',
|
205
|
+
border: false
|
206
|
+
),
|
207
|
+
height: '40%',
|
208
|
+
border: false
|
209
|
+
)
|
210
|
+
]
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.field_maker(namestr, h, meth)
|
214
|
+
name = namestr.to_sym
|
215
|
+
attribute name do |c|
|
216
|
+
c.width = h[:width] || 150
|
217
|
+
case h[:type]
|
218
|
+
when :datetime; c.format = 'Y-m-d H:i'
|
219
|
+
when :date; c.format = 'Y-m-d'
|
220
|
+
else c.type = h[:type] || :string
|
221
|
+
end
|
222
|
+
c.label = h[:label] if h[:label]
|
223
|
+
if h[:enum]
|
224
|
+
if h[:multi]
|
225
|
+
enum_array(c, h[:enum])
|
226
|
+
else
|
227
|
+
enum_column(c, h[:enum])
|
228
|
+
end
|
229
|
+
end
|
230
|
+
# for some unexplained reason the getter/setter need the full
|
231
|
+
# class qualification
|
232
|
+
if h[:type] != :range
|
233
|
+
c.getter = Marty::DeloreanRuleView.jsonb_field_getter(meth, namestr)
|
234
|
+
c.setter = Marty::DeloreanRuleView.jsonb_field_setter(meth, namestr)
|
235
|
+
c.filter_with = lambda do |rel, value, op|
|
236
|
+
v = ActiveRecord::Base.connection.quote(value)[1..-2]
|
237
|
+
rel.where("#{meth}->>'#{namestr}' like '%#{v}%'")
|
238
|
+
end
|
239
|
+
else
|
240
|
+
c.getter = range_getter(namestr, meth)
|
241
|
+
c.setter = range_setter(namestr, meth)
|
242
|
+
c.filterable = false
|
243
|
+
end
|
244
|
+
c.sorting_scope = get_json_sorter(meth, namestr)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
attribute :start_dt do |c|
|
249
|
+
c.width = 100
|
250
|
+
c.format = 'Y-m-d H:i'
|
251
|
+
end
|
252
|
+
|
253
|
+
attribute :end_dt do |c|
|
254
|
+
c.width = 100
|
255
|
+
c.format = 'Y-m-d H:i'
|
256
|
+
end
|
257
|
+
|
258
|
+
attribute :rule_type do |c|
|
259
|
+
c.width = 200
|
260
|
+
end
|
261
|
+
|
262
|
+
def self.init_fields
|
263
|
+
klass.guard_info.each do |namestr, h|
|
264
|
+
field_maker(namestr, h, :simple_guards)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
computed_fields.each do |a|
|
269
|
+
column a do |c|
|
270
|
+
c.flex = 1
|
271
|
+
c.getter = jsonb_getter(a.to_s)
|
272
|
+
c.sorting_scope = json_sort_scope(a)
|
273
|
+
c.filter_with = lambda do |rel, value, op|
|
274
|
+
v = ActiveRecord::Base.connection.quote(value)[1..-2]
|
275
|
+
rel.where("#{a}::text like '%#{v}%'")
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Marty::DeloreanRuleView < Marty::BaseRuleView
|
2
|
+
include Marty::Extras::Layout
|
3
|
+
|
4
|
+
def self.klass
|
5
|
+
Marty::DeloreanRule
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.base_fields
|
9
|
+
super + [:rule_type, :start_dt, :end_dt]
|
10
|
+
end
|
11
|
+
|
12
|
+
attribute :start_dt do |c|
|
13
|
+
c.width = 150
|
14
|
+
c.format = 'Y-m-d H:i'
|
15
|
+
end
|
16
|
+
|
17
|
+
attribute :end_dt do |c|
|
18
|
+
c.width = 150
|
19
|
+
c.format = 'Y-m-d H:i'
|
20
|
+
end
|
21
|
+
|
22
|
+
attribute :rule_type do |c|
|
23
|
+
c.width = 200
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -154,15 +154,30 @@ module Layout
|
|
154
154
|
######################################################################
|
155
155
|
# make sure to validate range vals on the model (e.g. see rule.rb)
|
156
156
|
|
157
|
-
def range_getter(name)
|
158
|
-
|
159
|
-
Marty::Util.pg_range_to_human(r.send(name)
|
160
|
-
|
157
|
+
def range_getter(name, json_field=nil)
|
158
|
+
if json_field
|
159
|
+
lambda { |r| Marty::Util.pg_range_to_human(r.send(json_field)[name]) }
|
160
|
+
else
|
161
|
+
lambda { |r| Marty::Util.pg_range_to_human(r.send(name)) }
|
162
|
+
end
|
161
163
|
end
|
162
164
|
|
163
|
-
def range_setter(name)
|
164
|
-
|
165
|
-
r
|
165
|
+
def range_setter(name, json_field=nil)
|
166
|
+
if json_field
|
167
|
+
lambda do |r, v|
|
168
|
+
cookedv = v && v.present? && (Marty::Util.human_to_pg_range(v) rescue v)
|
169
|
+
h = r.send(json_field)
|
170
|
+
if cookedv
|
171
|
+
r.send("#{json_field}=", h + {name=>cookedv})
|
172
|
+
else
|
173
|
+
h.delete(name)
|
174
|
+
r.send("#{json_field}=", h)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
else
|
178
|
+
lambda do |r, v|
|
179
|
+
r.send("#{name}=", v && (Marty::Util.human_to_pg_range(v) rescue v))
|
180
|
+
end
|
166
181
|
end
|
167
182
|
end
|
168
183
|
|
@@ -43,6 +43,59 @@ class Marty::McflyGridPanel < Marty::Grid
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
client_class do |c|
|
47
|
+
c.init_component = l(<<-JS)
|
48
|
+
function() {
|
49
|
+
this.callParent();
|
50
|
+
|
51
|
+
// dup is a non standard button, so we have to explicitly manage
|
52
|
+
// its clickability
|
53
|
+
this.getSelectionModel().on('selectionchange', function(selModel) {
|
54
|
+
this.actions.dupInForm &&
|
55
|
+
this.actions.dupInForm.setDisabled(!selModel.hasSelection() ||
|
56
|
+
!this.permissions.create);
|
57
|
+
}, this);
|
58
|
+
}
|
59
|
+
JS
|
60
|
+
end
|
61
|
+
|
62
|
+
client_class do |c|
|
63
|
+
c.include :dup_in_form
|
64
|
+
end
|
65
|
+
|
66
|
+
action :dup_in_form do |a|
|
67
|
+
a.hidden = !config[:permissions][:create]
|
68
|
+
a.icon = :page_copy
|
69
|
+
a.disabled = true
|
70
|
+
end
|
71
|
+
|
72
|
+
# edit-in-form submit with dup support
|
73
|
+
endpoint :edit_window__edit_form__submit do |params|
|
74
|
+
|
75
|
+
if params["dup"]
|
76
|
+
# FIXME: copied from basepack grid endpoint
|
77
|
+
# :add_window__add_form__netzke_submit
|
78
|
+
|
79
|
+
params[:data] = ActiveSupport::JSON.
|
80
|
+
decode(params[:data]).merge(id: nil).to_json
|
81
|
+
|
82
|
+
client.merge!(component_instance(:add_window).
|
83
|
+
component_instance(:add_form).
|
84
|
+
invoke_endpoint(:submit, [params]))
|
85
|
+
|
86
|
+
on_data_changed if client.netzke_set_form_values.present?
|
87
|
+
client.delete(:netzke_set_form_values)
|
88
|
+
else
|
89
|
+
# FIXME: copied from basepack grid endpoint
|
90
|
+
# :edit_window__edit_form__netzke_submit
|
91
|
+
client.merge!(component_instance(:edit_window).
|
92
|
+
component_instance(:edit_form).
|
93
|
+
invoke_endpoint(:submit, [params]))
|
94
|
+
on_data_changed if client.netzke_set_form_values.present?
|
95
|
+
client.delete(:netzke_set_form_values)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
46
99
|
private
|
47
100
|
def self.mcfly_scope(sort_column)
|
48
101
|
lambda { |r|
|