engine2 1.0.4 → 1.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +0 -0
- data/Rakefile +4 -4
- data/app/{engine2actions.coffee → actions.coffee} +341 -215
- data/app/app.coffee +0 -0
- data/app/app.css +17 -0
- data/app/engine2.coffee +158 -208
- data/app/modal.coffee +138 -0
- data/bower.json +4 -2
- data/conf/message.yaml +5 -0
- data/conf/message_pl.yaml +7 -2
- data/config.coffee +24 -12
- data/engine2.gemspec +8 -8
- data/lib/engine2.rb +12 -10
- data/lib/engine2/action.rb +1338 -133
- data/lib/engine2/action/array.rb +189 -0
- data/lib/engine2/{meta/decode_meta.rb → action/decode.rb} +52 -21
- data/lib/engine2/action/delete.rb +64 -0
- data/lib/engine2/action/form.rb +16 -0
- data/lib/engine2/{meta/infra_meta.rb → action/infra.rb} +123 -89
- data/lib/engine2/action/link.rb +117 -0
- data/lib/engine2/action/list.rb +333 -0
- data/lib/engine2/action/save.rb +28 -0
- data/lib/engine2/action/view.rb +8 -0
- data/lib/engine2/action_node.rb +221 -0
- data/lib/engine2/core.rb +175 -87
- data/lib/engine2/handler.rb +14 -13
- data/lib/engine2/model.rb +85 -43
- data/lib/engine2/models/Files.rb +4 -1
- data/lib/engine2/models/UserInfo.rb +6 -3
- data/lib/engine2/post_bootstrap.rb +4 -3
- data/lib/engine2/pre_bootstrap.rb +10 -6
- data/lib/engine2/scheme.rb +107 -65
- data/lib/engine2/templates.rb +41 -6
- data/lib/engine2/type_info.rb +51 -23
- data/lib/engine2/version.rb +2 -1
- data/package.json +22 -16
- data/public/favicon.ico +0 -0
- data/public/img/ajax-loader-dark.gif +0 -0
- data/public/img/ajax-loader.gif +0 -0
- data/views/fields/blob.slim +1 -1
- data/views/fields/bs_select.slim +2 -2
- data/views/fields/bsselect_picker.slim +4 -4
- data/views/fields/bsselect_picker_opt.slim +5 -5
- data/views/fields/checkbox.slim +4 -4
- data/views/fields/checkbox_button.slim +6 -0
- data/views/fields/checkbox_buttons.slim +3 -3
- data/views/fields/checkbox_buttons_opt.slim +3 -3
- data/views/fields/currency.slim +2 -2
- data/views/fields/date.slim +4 -4
- data/views/fields/date_range.slim +9 -9
- data/views/fields/date_time.slim +9 -9
- data/views/fields/datetime.slim +8 -8
- data/views/fields/decimal.slim +1 -1
- data/views/fields/decimal_date.slim +3 -3
- data/views/fields/decimal_time.slim +3 -3
- data/views/fields/email.slim +3 -3
- data/views/fields/file_store.slim +11 -11
- data/views/fields/input_text.slim +4 -4
- data/views/fields/integer.slim +1 -1
- data/views/fields/list_bsmselect.slim +20 -0
- data/views/fields/list_bsselect.slim +5 -5
- data/views/fields/list_bsselect_opt.slim +6 -6
- data/views/fields/list_buttons.slim +1 -1
- data/views/fields/list_buttons_opt.slim +2 -2
- data/views/fields/list_mbuttons.slim +9 -0
- data/views/fields/list_mbuttons_opt.slim +11 -0
- data/views/fields/list_mselect.slim +12 -0
- data/views/fields/list_select.slim +4 -4
- data/views/fields/list_select_opt.slim +5 -5
- data/views/fields/password.slim +4 -4
- data/views/fields/radio_checkbox.slim +3 -3
- data/views/fields/scaffold.slim +2 -2
- data/views/fields/scaffold_picker.slim +5 -5
- data/views/fields/select_picker.slim +3 -3
- data/views/fields/select_picker_opt.slim +4 -4
- data/views/fields/text_area.slim +4 -3
- data/views/fields/time.slim +5 -4
- data/views/fields/typeahead_picker.slim +12 -9
- data/views/index.slim +3 -3
- data/views/infra/index.slim +0 -0
- data/views/infra/inspect.slim +41 -10
- data/views/modals/close_m.slim +0 -0
- data/views/modals/confirm_m.slim +0 -0
- data/views/modals/empty_m.slim +0 -0
- data/views/modals/menu_m.slim +1 -1
- data/views/modals/yes_no_m.slim +0 -0
- data/views/panels/menu_m.slim +1 -1
- data/views/scaffold/confirm.slim +0 -0
- data/views/scaffold/fields.slim +6 -4
- data/views/scaffold/form.slim +1 -1
- data/views/scaffold/form_collapse.slim +4 -3
- data/views/scaffold/form_tabs.slim +3 -2
- data/views/scaffold/list.slim +0 -0
- data/views/scaffold/message.slim +0 -0
- data/views/scaffold/search.slim +4 -4
- data/views/scaffold/search_collapse.slim +8 -7
- data/views/scaffold/search_tabs.slim +6 -5
- data/views/scaffold/view.slim +2 -2
- data/views/scaffold/view_collapse.slim +5 -4
- data/views/scaffold/view_tabs.slim +4 -3
- data/views/search_fields/bsmselect_picker.slim +4 -4
- data/views/search_fields/bsselect_picker.slim +4 -4
- data/views/search_fields/checkbox.slim +3 -3
- data/views/search_fields/checkbox2.slim +5 -5
- data/views/search_fields/checkbox_buttons.slim +3 -3
- data/views/search_fields/date.slim +20 -0
- data/views/search_fields/date_range.slim +8 -8
- data/views/search_fields/decimal_date_range.slim +5 -5
- data/views/search_fields/input_text.slim +2 -2
- data/views/search_fields/integer.slim +1 -1
- data/views/search_fields/integer_range.slim +2 -2
- data/views/search_fields/list_bsmselect.slim +4 -4
- data/views/search_fields/list_bsselect.slim +4 -4
- data/views/search_fields/list_buttons.slim +2 -2
- data/views/search_fields/list_mbuttons.slim +12 -0
- data/views/search_fields/list_select.slim +3 -3
- data/views/search_fields/scaffold_picker.slim +2 -2
- data/views/search_fields/select_picker.slim +3 -3
- data/views/search_fields/typeahead_picker.slim +8 -7
- metadata +53 -48
- data/lib/engine2/meta.rb +0 -1216
- data/lib/engine2/meta/array_meta.rb +0 -82
- data/lib/engine2/meta/delete_meta.rb +0 -60
- data/lib/engine2/meta/form_meta.rb +0 -15
- data/lib/engine2/meta/link_meta.rb +0 -134
- data/lib/engine2/meta/list_meta.rb +0 -281
- data/lib/engine2/meta/save_meta.rb +0 -50
- data/lib/engine2/meta/view_meta.rb +0 -7
- data/public/__sinatra__/404.png +0 -0
- data/public/__sinatra__/500.png +0 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Engine2
|
5
|
+
class StarToManyLinkAction < Action
|
6
|
+
include ActionModelSupport
|
7
|
+
http_method :post
|
8
|
+
action_type :star_to_many_link
|
9
|
+
|
10
|
+
def pre_run
|
11
|
+
super
|
12
|
+
execute "action.errors || [action.parent().invoke(), action.panel_close()]"
|
13
|
+
end
|
14
|
+
|
15
|
+
def invoke handler
|
16
|
+
json = handler.post_to_json
|
17
|
+
parent = json[:parent_id]
|
18
|
+
ids = json[:ids]
|
19
|
+
handler.permit parent && ids
|
20
|
+
invoke_link_db handler, split_keys(parent), ids
|
21
|
+
end
|
22
|
+
|
23
|
+
def invoke_link_db handler, parent, ids
|
24
|
+
model = assets[:model]
|
25
|
+
assoc = assets[:assoc]
|
26
|
+
|
27
|
+
case assoc[:type]
|
28
|
+
when :one_to_many
|
29
|
+
model.db.transaction do
|
30
|
+
pk = Hash[assoc[:keys].zip(parent)]
|
31
|
+
ids.each do |id|
|
32
|
+
model.where(model.primary_keys_hash(split_keys(id))).update(pk)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
when :many_to_many
|
36
|
+
p_pk = Hash[assoc[:left_keys].zip(parent)]
|
37
|
+
values = ids.map do |id|
|
38
|
+
p_pk.merge Hash[assoc[:right_keys].zip(split_keys(id))]
|
39
|
+
end
|
40
|
+
model.db[assoc[:join_table]].multi_insert values
|
41
|
+
else unsupported_association
|
42
|
+
end
|
43
|
+
{}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class StarToManyUnlinkActionBase < Action
|
48
|
+
include ActionModelSupport
|
49
|
+
http_method :delete
|
50
|
+
|
51
|
+
def pre_run
|
52
|
+
super
|
53
|
+
execute "[action.parent().invoke(), action.panel_close()]"
|
54
|
+
end
|
55
|
+
|
56
|
+
def invoke_unlink_db handler, parent, ids
|
57
|
+
model = assets[:model]
|
58
|
+
assoc = assets[:assoc]
|
59
|
+
|
60
|
+
case assoc[:type]
|
61
|
+
when :one_to_many
|
62
|
+
keys = assoc[:keys]
|
63
|
+
if keys.all?{|k|model.db_schema[k][:allow_null] == true}
|
64
|
+
model.db.transaction do
|
65
|
+
ids.each do |id|
|
66
|
+
model.where(model.primary_keys_hash(split_keys(id))).update(Hash[keys.zip([nil])])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
else
|
70
|
+
handler.halt_method_not_allowed LOCS[:"non_nullable"]
|
71
|
+
end
|
72
|
+
when :many_to_many
|
73
|
+
model.db.transaction do
|
74
|
+
p_pk = Hash[assoc[:left_keys].zip(parent)]
|
75
|
+
ds = model.db[assoc[:join_table]]
|
76
|
+
ids.each do |id|
|
77
|
+
ds.where(p_pk & Hash[assoc[:right_keys].zip(split_keys(id))]).delete
|
78
|
+
end
|
79
|
+
end
|
80
|
+
else unsupported_association
|
81
|
+
end
|
82
|
+
{}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class StarToManyUnlinkAction < StarToManyUnlinkActionBase
|
87
|
+
action_type :star_to_many_unlink
|
88
|
+
|
89
|
+
def pre_run
|
90
|
+
super
|
91
|
+
node.parent.parent.*.menu(:item_menu).option :confirm_unlink, icon: "minus", show: "action.selected_size() == 0", button_loc: false
|
92
|
+
end
|
93
|
+
|
94
|
+
def invoke handler
|
95
|
+
handler.permit id = handler.params[:id]
|
96
|
+
handler.permit parent = handler.params[:parent_id]
|
97
|
+
invoke_unlink_db handler, split_keys(parent), [id]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class StarToManyBulkUnlinkAction < StarToManyUnlinkActionBase
|
102
|
+
action_type :star_to_many_bulk_unlink
|
103
|
+
|
104
|
+
def pre_run
|
105
|
+
super
|
106
|
+
node.parent.parent.*.select_toggle_menu
|
107
|
+
node.parent.parent.*.menu(:menu).option_after :default_order, :confirm_bulk_unlink, icon: "minus", show: "action.selected_size() > 0", button_loc: false
|
108
|
+
end
|
109
|
+
|
110
|
+
def invoke handler
|
111
|
+
ids = handler.param_to_json(:ids)
|
112
|
+
handler.permit parent = handler.params[:parent_id]
|
113
|
+
handler.permit ids.is_a?(Array)
|
114
|
+
invoke_unlink_db handler, split_keys(parent), ids
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,333 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Engine2
|
5
|
+
class ListAction < Action
|
6
|
+
action_type :list
|
7
|
+
include ActionListSupport, ActionQuerySupport
|
8
|
+
|
9
|
+
(DefaultFilters ||= {}).merge!(
|
10
|
+
string: lambda{|query, name, value, type_info, hash|
|
11
|
+
case type_info[:type]
|
12
|
+
when :list_select
|
13
|
+
raise E2Error.new("Filter unimplemented for string multi list_select, field: '#{name.to_sym}'") if type_info[:multiselect] # todo
|
14
|
+
query.where(name => value)
|
15
|
+
when :many_to_one
|
16
|
+
query.where(name => value)
|
17
|
+
else
|
18
|
+
query.where(name.like("%#{value}%"))
|
19
|
+
end
|
20
|
+
},
|
21
|
+
date: lambda{|query, name, value, type_info, hash|
|
22
|
+
if value.is_a? Hash
|
23
|
+
from, to = value[:from], value[:to]
|
24
|
+
if from && to
|
25
|
+
query.where(name => from .. to)
|
26
|
+
elsif from
|
27
|
+
query.where(name >= Sequel.string_to_date(from))
|
28
|
+
elsif to
|
29
|
+
query.where(name <= Sequel.string_to_date(to))
|
30
|
+
else
|
31
|
+
query # ?
|
32
|
+
end
|
33
|
+
else
|
34
|
+
query.where(name => Sequel.string_to_date(value))
|
35
|
+
end
|
36
|
+
},
|
37
|
+
datetime: lambda{|query, name, value, type_info, hash|
|
38
|
+
if value.is_a? Hash
|
39
|
+
DefaultFilters[:date].(query, name, value, type_info, hash)
|
40
|
+
else
|
41
|
+
query.where(:date.sql_function(name) => Sequel.string_to_date(value))
|
42
|
+
end
|
43
|
+
},
|
44
|
+
integer: lambda{|query, name, value, type_info, hash|
|
45
|
+
if value.is_a? Hash
|
46
|
+
from, to = value[:from], value[:to]
|
47
|
+
if from && to
|
48
|
+
query.where(name => from .. to)
|
49
|
+
else
|
50
|
+
query.where(from ? name >= from.to_i : name <= to.to_i)
|
51
|
+
end
|
52
|
+
elsif value.is_a?(Integer) || value.is_a?(String)
|
53
|
+
query.where(name => value.to_i)
|
54
|
+
elsif value.is_a? Array
|
55
|
+
if !value.empty?
|
56
|
+
case type_info[:type]
|
57
|
+
when :many_to_one
|
58
|
+
keys = type_info[:keys]
|
59
|
+
if keys.length == 1
|
60
|
+
query.where(name => value)
|
61
|
+
else
|
62
|
+
query.where(keys.map{|k| hash[k]}.transpose.map{|vals| Hash[keys.zip(vals)]}.reduce{|q, c| q | c})
|
63
|
+
end
|
64
|
+
when :list_select
|
65
|
+
if type_info[:multiselect]
|
66
|
+
query.where(~{(name.sql_number & value.reduce(0, :|)) => 0})
|
67
|
+
else
|
68
|
+
query.where(name => value) # decode in sql query ?
|
69
|
+
end
|
70
|
+
when :integer
|
71
|
+
query
|
72
|
+
else
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
else
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
else
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
},
|
82
|
+
boolean: lambda{|query, name, value, type_info, hash|
|
83
|
+
query.where(name => value)
|
84
|
+
}
|
85
|
+
)
|
86
|
+
|
87
|
+
def post_run
|
88
|
+
query select(*assets[:model].columns.reject{|col| assets[:model].type_info[col][:length].to_i > 20}.take(10)) unless @query
|
89
|
+
super
|
90
|
+
end
|
91
|
+
|
92
|
+
def page_frame handler, entries
|
93
|
+
entries
|
94
|
+
end
|
95
|
+
|
96
|
+
def invoke handler
|
97
|
+
params = handler.params
|
98
|
+
model = assets[:model]
|
99
|
+
query = list_context(get_query, handler)
|
100
|
+
|
101
|
+
if search = params[:search]
|
102
|
+
query = list_search(query, handler, search)
|
103
|
+
elsif @filters || static.filters
|
104
|
+
static.filters.to_h.merge(@filters.to_h).each do |name, filter|
|
105
|
+
query = filter.(handler, query, {})
|
106
|
+
handler.permit query
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
count = query.count if lookup(:config, :use_count)
|
111
|
+
|
112
|
+
if order = params[:order]
|
113
|
+
order = order.to_sym
|
114
|
+
handler.permit lookup(:fields, order, :sort)
|
115
|
+
query = list_order(query, handler, order, params[:asc] == "true")
|
116
|
+
elsif order = @default_order_field || static.default_order_field
|
117
|
+
query = list_order(query, handler, order, true)
|
118
|
+
end
|
119
|
+
|
120
|
+
per_page = lookup(:config, :per_page)
|
121
|
+
page = params[:page].to_i
|
122
|
+
handler.permit page >= 0 && page < 1000000
|
123
|
+
|
124
|
+
query = query.limit(per_page, page)
|
125
|
+
|
126
|
+
res = {entries: page_frame(handler, query.load_all)}
|
127
|
+
res[:count] = count if count
|
128
|
+
res
|
129
|
+
end
|
130
|
+
|
131
|
+
def list_search query, handler, search
|
132
|
+
hash = JSON.parse(search, symbolize_names: true) rescue handler.halt_forbidden
|
133
|
+
model = assets[:model]
|
134
|
+
sfields = lookup(:search_field_list)
|
135
|
+
handler.permit sfields
|
136
|
+
|
137
|
+
filters = @filters || static.filters ? static.filters.to_h.merge(@filters.to_h) : {}
|
138
|
+
|
139
|
+
sfields.each do |name|
|
140
|
+
type_info = model.find_type_info(name)
|
141
|
+
name = name.to_sym
|
142
|
+
filter = filters[name]
|
143
|
+
if !(value = hash[name]).nil? # use key?
|
144
|
+
query = if filter
|
145
|
+
filter.(handler, query, hash)
|
146
|
+
elsif filter = DefaultFilters[type_info[:otype]]
|
147
|
+
name = model.type_info[name] ? model.table_name.q(name) : Sequel.expr(name)
|
148
|
+
filter.(query, name, value, type_info, hash)
|
149
|
+
else
|
150
|
+
raise E2Error.new("Filter not found for field '#{name}' in model '#{model}'") unless filter
|
151
|
+
end
|
152
|
+
handler.permit query
|
153
|
+
else
|
154
|
+
if filter
|
155
|
+
query = filter.(handler, query, hash)
|
156
|
+
handler.permit query
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# hash.each_pair do |name, value|
|
162
|
+
# handler.permit name = sfields.find{|sf|sf.to_sym == name}
|
163
|
+
# type_info = model.find_type_info(name)
|
164
|
+
# query = if filter = (@filters && @filters[name]) || (dynamic? && (static.filters && static.filters[name]))
|
165
|
+
# filter.(handler, query, hash)
|
166
|
+
# elsif filter = DefaultFilters[type_info[:otype]]
|
167
|
+
# name = model.type_info[name] ? model.table_name.q(name) : Sequel.expr(name)
|
168
|
+
# filter.(query, name, value, type_info, hash)
|
169
|
+
# else
|
170
|
+
# raise E2Error.new("Filter not found for field '#{name}' in model '#{model}'") unless filter
|
171
|
+
# end
|
172
|
+
# handler.permit query
|
173
|
+
# end
|
174
|
+
|
175
|
+
query
|
176
|
+
end
|
177
|
+
|
178
|
+
def list_order query, handler, order, asc
|
179
|
+
model = assets[:model]
|
180
|
+
query = if order_blk = (@orders && @orders[order]) || (dynamic? && (static.orders && static.orders[order]))
|
181
|
+
order_blk.(handler, query)
|
182
|
+
else
|
183
|
+
order = model.table_name.q(order) if model.type_info[order]
|
184
|
+
query.order(order)
|
185
|
+
end
|
186
|
+
|
187
|
+
asc ? query : query.reverse
|
188
|
+
end
|
189
|
+
|
190
|
+
def list_context query, handler
|
191
|
+
query
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
#
|
196
|
+
# Many to One
|
197
|
+
#
|
198
|
+
class ManyToOneListAction < ListAction
|
199
|
+
action_type :many_to_one_list
|
200
|
+
|
201
|
+
def pre_run
|
202
|
+
super
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
#
|
207
|
+
# * to Many
|
208
|
+
#
|
209
|
+
class StarToManyListAction < ListAction
|
210
|
+
action_type :star_to_many_list
|
211
|
+
def pre_run
|
212
|
+
super
|
213
|
+
menu(:panel_menu).option_at 0, :close, icon: "remove"
|
214
|
+
panel_title "#{assets[:model].model_icon.icon} #{LOCS[assets[:assoc][:name]]}"
|
215
|
+
end
|
216
|
+
|
217
|
+
def list_context query, handler
|
218
|
+
handler.permit parent = handler.params[:parent_id]
|
219
|
+
model = assets[:model]
|
220
|
+
assoc = assets[:assoc]
|
221
|
+
parent_keys = split_keys(parent)
|
222
|
+
case assoc[:type]
|
223
|
+
when :one_to_many
|
224
|
+
keys = assoc[:keys]
|
225
|
+
condition = parent_keys.all?(&:empty?) ? false : Hash[keys.map{|k| model.table_name.q(k)}.zip(parent_keys)]
|
226
|
+
if handler.params[:negate]
|
227
|
+
query = query.exclude(condition)
|
228
|
+
query = query.or(Hash[keys.zip([nil])]) if keys.all?{|k|model.db_schema[k][:allow_null] == true} # type_info[:required] ?
|
229
|
+
query
|
230
|
+
else
|
231
|
+
query.where(condition)
|
232
|
+
end
|
233
|
+
when :many_to_many
|
234
|
+
q_pk = model.primary_keys_qualified
|
235
|
+
j_table = assoc[:join_table]
|
236
|
+
l_keys = assoc[:left_keys].map{|k| j_table.q(k)}
|
237
|
+
r_keys = assoc[:right_keys].map{|k| j_table.q(k)}
|
238
|
+
r_keys_vals = Hash[r_keys.zip(q_pk)]
|
239
|
+
l_keys_vals = parent_keys.all?(&:empty?) ? false : Hash[l_keys.zip(parent_keys)]
|
240
|
+
|
241
|
+
if handler.params[:negate]
|
242
|
+
query.exclude(model.db[j_table].select(nil).where(r_keys_vals & l_keys_vals).exists)
|
243
|
+
else
|
244
|
+
# query.qualify.join(j_table, [r_keys_vals, l_keys_vals])
|
245
|
+
if joins = query.opts[:join] and joins.find{|j|j.table == j_table}
|
246
|
+
query
|
247
|
+
else
|
248
|
+
query.qualify.left_join(j_table, r_keys_vals)
|
249
|
+
end.filter(l_keys_vals)
|
250
|
+
end
|
251
|
+
else unsupported_association
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def post_run
|
256
|
+
super
|
257
|
+
nd = node.parent.nodes[:decode_entry]
|
258
|
+
request do |h|
|
259
|
+
if h.initial?
|
260
|
+
action = nd.*
|
261
|
+
rec = action.invoke_decode(h, [split_keys(h.params[:parent_id])]).first
|
262
|
+
panel_title "#{static.panel[:title]} - #{action.meta[:decode_fields].map{|f|rec[f]}.join(action.meta[:separator])}"
|
263
|
+
end
|
264
|
+
end if nd
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
class StarToManyLinkListAction < StarToManyListAction
|
269
|
+
action_type :star_to_many_link_list
|
270
|
+
def pre_run
|
271
|
+
super
|
272
|
+
panel_title LOCS[:link_title]
|
273
|
+
menu(:panel_menu).option_at 0, :link, icon: "ok", enabled: "action.selected_size() > 0"
|
274
|
+
node.parent.*.menu(:menu).option_at 0, :link_list, icon: "paperclip", button_loc: false
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# *_to_many_field
|
279
|
+
class StarToManyFieldAction < StarToManyListAction
|
280
|
+
action_type :star_to_many_field
|
281
|
+
|
282
|
+
def pre_run
|
283
|
+
super
|
284
|
+
modal_action false
|
285
|
+
panel_panel_template false
|
286
|
+
end
|
287
|
+
|
288
|
+
def list_context query, handler
|
289
|
+
changes = handler.param_to_json(:changes)
|
290
|
+
model = assets[:model]
|
291
|
+
unlinked = changes[:unlink].to_a + changes[:delete].to_a + changes[:modify].to_a.map{|m|join_keys(model.primary_keys.map{|k|m[k]})}
|
292
|
+
linked = changes[:link]
|
293
|
+
query = super(query, handler)
|
294
|
+
|
295
|
+
pks = model.primary_keys_qualified
|
296
|
+
|
297
|
+
if handler.params[:negate]
|
298
|
+
query = unlinked.reduce(query){|q, unl|q.or pks.zip(split_keys(unl))}
|
299
|
+
query = linked.reduce(query){|q, ln|q.where(pks.zip(split_keys(ln)).sql_negate)}
|
300
|
+
else
|
301
|
+
query = unlinked.reduce(query){|q, unl|q.where(pks.zip(split_keys(unl)).sql_negate)}
|
302
|
+
query = case assets[:assoc][:type]
|
303
|
+
when :one_to_many
|
304
|
+
linked.reduce(query){|q, ln|q.or pks.zip(split_keys(ln))}
|
305
|
+
when :many_to_many
|
306
|
+
linked.reduce(query){|q, ln|q.or pks.zip(split_keys(ln))}.distinct
|
307
|
+
else unsupported_association
|
308
|
+
end unless linked.empty?
|
309
|
+
end
|
310
|
+
|
311
|
+
added = changes[:create].to_a + changes[:modify].to_a
|
312
|
+
cols = get_query.columns
|
313
|
+
query = added.reduce query do |q, a|
|
314
|
+
q.union(model.db.select(*cols.map{|c|a[c]}), all: true, alias: model.table_name)
|
315
|
+
end
|
316
|
+
|
317
|
+
query
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
class StarToManyFieldLinkListAction < StarToManyFieldAction
|
322
|
+
action_type :star_to_many_field_link_list
|
323
|
+
|
324
|
+
def pre_run
|
325
|
+
super
|
326
|
+
modal_action true
|
327
|
+
panel_panel_template nil
|
328
|
+
panel_title LOCS[:link_title]
|
329
|
+
menu(:panel_menu).option_at 0, :link, icon: "ok", enabled: "action.selected_size() > 0"
|
330
|
+
node.parent.*.menu(:menu).option_at 0, :link_list, icon: "paperclip", button_loc: false
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Engine2
|
5
|
+
class SaveAction < Action
|
6
|
+
include ActionSaveSupport
|
7
|
+
end
|
8
|
+
|
9
|
+
class InsertAction < SaveAction
|
10
|
+
include ActionInsertSupport
|
11
|
+
action_type :approve
|
12
|
+
end
|
13
|
+
|
14
|
+
class UpdateAction < SaveAction
|
15
|
+
include ActionUpdateSupport
|
16
|
+
action_type :approve
|
17
|
+
end
|
18
|
+
|
19
|
+
class StarToManyFieldInsertAction < InsertAction
|
20
|
+
self.validate_only = true
|
21
|
+
action_type :star_to_many_field_approve
|
22
|
+
end
|
23
|
+
|
24
|
+
class StarToManyFieldUpdateAction < UpdateAction
|
25
|
+
self.validate_only = true
|
26
|
+
action_type :star_to_many_field_approve
|
27
|
+
end
|
28
|
+
end
|