engine2 1.0.8 → 1.0.9
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/Rakefile +3 -3
- data/app/actions.coffee +87 -50
- data/app/app.css +2 -1
- data/app/engine2.coffee +37 -19
- data/app/modal.coffee +8 -3
- data/bower.json +3 -2
- data/conf/message.yaml +3 -0
- data/conf/message_pl.yaml +5 -2
- data/config.coffee +16 -15
- data/engine2.gemspec +1 -1
- data/lib/engine2/action.rb +51 -23
- data/lib/engine2/action/array.rb +94 -1
- data/lib/engine2/action/decode.rb +29 -3
- data/lib/engine2/action/delete.rb +1 -2
- data/lib/engine2/action/infra.rb +5 -4
- data/lib/engine2/action/list.rb +70 -25
- data/lib/engine2/action/save.rb +0 -2
- data/lib/engine2/action_node.rb +2 -4
- data/lib/engine2/core.rb +30 -21
- data/lib/engine2/handler.rb +5 -5
- data/lib/engine2/model.rb +18 -9
- data/lib/engine2/models/Files.rb +2 -0
- data/lib/engine2/scheme.rb +1 -6
- data/lib/engine2/templates.rb +32 -6
- data/lib/engine2/type_info.rb +9 -5
- data/lib/engine2/version.rb +1 -1
- data/package.json +9 -8
- data/views/fields/checkbox_button.slim +6 -0
- data/views/fields/checkbox_buttons.slim +1 -1
- 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/scaffold.slim +1 -1
- data/views/fields/typeahead_picker.slim +8 -5
- data/views/infra/inspect.slim +19 -16
- data/views/scaffold/fields.slim +3 -1
- data/views/scaffold/search.slim +2 -2
- data/views/scaffold/search_collapse.slim +2 -2
- data/views/scaffold/search_tabs.slim +2 -2
- data/views/search_fields/date.slim +20 -0
- data/views/search_fields/list_mbuttons.slim +12 -0
- data/views/search_fields/typeahead_picker.slim +4 -3
- metadata +11 -5
@@ -57,6 +57,10 @@ module Engine2
|
|
57
57
|
def invoke handler
|
58
58
|
{entries: get_query.limit(200).load_all}
|
59
59
|
end
|
60
|
+
|
61
|
+
def order *fields
|
62
|
+
@query = get_query.order *fields
|
63
|
+
end
|
60
64
|
end
|
61
65
|
|
62
66
|
class TypeAheadAction < DecodeAction
|
@@ -71,17 +75,39 @@ module Engine2
|
|
71
75
|
@limit = lmt
|
72
76
|
end
|
73
77
|
|
78
|
+
def get_limit
|
79
|
+
@limit
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_case_insensitive
|
83
|
+
@case_insensitive
|
84
|
+
end
|
85
|
+
|
74
86
|
def case_insensitive
|
75
87
|
@case_insensitive = true
|
76
88
|
end
|
77
89
|
|
90
|
+
def order *fields
|
91
|
+
@query = get_query.order *fields
|
92
|
+
end
|
93
|
+
|
78
94
|
def invoke handler
|
95
|
+
model = assets[:model]
|
79
96
|
if query = handler.params[:query]
|
80
|
-
|
81
|
-
|
97
|
+
fields = @meta[:decode_fields] || static.meta[:decode_fields]
|
98
|
+
|
99
|
+
entries = if query.to_s.empty?
|
100
|
+
get_query
|
101
|
+
else
|
102
|
+
table_name = model.table_name
|
103
|
+
condition = fields.map{|f|table_name.q(f).like("%#{query}%", case_insensitive: @case_insensitive || static.get_case_insensitive)}.reduce{|q, f| q | f}
|
104
|
+
get_query.where(condition)
|
105
|
+
end.limit(@limit || static.get_limit).load_all
|
106
|
+
|
107
|
+
{entries: entries}
|
82
108
|
else
|
83
109
|
handler.permit id = handler.params[:id]
|
84
|
-
record = get_query.load Hash[
|
110
|
+
record = get_query.unordered.load Hash[model.primary_keys_qualified.zip(split_keys(id))]
|
85
111
|
# handler.halt_not_found(LOCS[:no_entry]) unless record
|
86
112
|
{entry: record}
|
87
113
|
end
|
data/lib/engine2/action/infra.rb
CHANGED
@@ -24,7 +24,7 @@ module Engine2
|
|
24
24
|
|
25
25
|
define_node :inspect_modal, InspectModalAction do
|
26
26
|
access! &:logged_in?
|
27
|
-
define_node :
|
27
|
+
define_node :"inspect_#{SETTINGS[:name]}", WebSocketAction.inherit do
|
28
28
|
self.* do
|
29
29
|
@action_type = :inspect
|
30
30
|
|
@@ -112,7 +112,8 @@ module Engine2
|
|
112
112
|
temp.close
|
113
113
|
rackname = File.basename(temp.path)
|
114
114
|
info = node.parent.*.model.type_info[node.parent.*.field]
|
115
|
-
File.rename(temp.path, "#{info[:store][:upload]}/#{rackname}")
|
115
|
+
FileUtils.cp(temp.path, "#{info[:store][:upload]}/#{rackname}") # File.rename(temp.path, "#{info[:store][:upload]}/#{rackname}")
|
116
|
+
FileUtils.rm(temp.path)
|
116
117
|
{rackname: rackname}
|
117
118
|
end
|
118
119
|
end
|
@@ -233,9 +234,9 @@ module Engine2
|
|
233
234
|
{user: user ? user.to_hash : nil}
|
234
235
|
end
|
235
236
|
|
236
|
-
def login_meta
|
237
|
+
def login_meta menu_properties = {show: 'false'}, &blk
|
237
238
|
node.login_form.* &blk
|
238
|
-
menu(:menu).modify_option :login_form,
|
239
|
+
menu(:menu).modify_option :login_form, menu_properties
|
239
240
|
node.parent.login_form.* &blk
|
240
241
|
end
|
241
242
|
end
|
data/lib/engine2/action/list.rb
CHANGED
@@ -34,6 +34,13 @@ module Engine2
|
|
34
34
|
query.where(name => Sequel.string_to_date(value))
|
35
35
|
end
|
36
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
|
+
},
|
37
44
|
integer: lambda{|query, name, value, type_info, hash|
|
38
45
|
if value.is_a? Hash
|
39
46
|
from, to = value[:from], value[:to]
|
@@ -82,6 +89,10 @@ module Engine2
|
|
82
89
|
super
|
83
90
|
end
|
84
91
|
|
92
|
+
def page_frame handler, entries
|
93
|
+
entries
|
94
|
+
end
|
95
|
+
|
85
96
|
def invoke handler
|
86
97
|
params = handler.params
|
87
98
|
model = assets[:model]
|
@@ -89,31 +100,30 @@ module Engine2
|
|
89
100
|
|
90
101
|
if search = params[:search]
|
91
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
|
92
108
|
end
|
93
109
|
|
94
110
|
count = query.count if lookup(:config, :use_count)
|
95
111
|
|
96
|
-
if
|
97
|
-
order =
|
112
|
+
if order = params[:order]
|
113
|
+
order = order.to_sym
|
98
114
|
handler.permit lookup(:fields, order, :sort)
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
else
|
103
|
-
order = model.table_name.q(order) if model.type_info[order]
|
104
|
-
query = query.order(order)
|
105
|
-
end
|
106
|
-
|
107
|
-
query = query.reverse if params[:asc] == "true"
|
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)
|
108
118
|
end
|
109
119
|
|
110
120
|
per_page = lookup(:config, :per_page)
|
111
121
|
page = params[:page].to_i
|
112
|
-
handler.permit page >= 0 && page <
|
122
|
+
handler.permit page >= 0 && page < 1000000
|
113
123
|
|
114
124
|
query = query.limit(per_page, page)
|
115
125
|
|
116
|
-
res = {entries: query.load_all}
|
126
|
+
res = {entries: page_frame(handler, query.load_all)}
|
117
127
|
res[:count] = count if count
|
118
128
|
res
|
119
129
|
end
|
@@ -123,24 +133,60 @@ module Engine2
|
|
123
133
|
model = assets[:model]
|
124
134
|
sfields = lookup(:search_field_list)
|
125
135
|
handler.permit sfields
|
126
|
-
hash.each_pair do |name, value|
|
127
|
-
handler.permit name = sfields.find{|sf|sf.to_sym == name}
|
128
136
|
|
137
|
+
filters = @filters || static.filters ? static.filters.to_h.merge(@filters.to_h) : {}
|
138
|
+
|
139
|
+
sfields.each do |name|
|
129
140
|
type_info = model.find_type_info(name)
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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
|
135
153
|
else
|
136
|
-
|
154
|
+
if filter
|
155
|
+
query = filter.(handler, query, hash)
|
156
|
+
handler.permit query
|
157
|
+
end
|
137
158
|
end
|
138
|
-
|
139
|
-
handler.permit query
|
140
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
|
+
|
141
175
|
query
|
142
176
|
end
|
143
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
|
+
|
144
190
|
def list_context query, handler
|
145
191
|
query
|
146
192
|
end
|
@@ -165,7 +211,7 @@ module Engine2
|
|
165
211
|
def pre_run
|
166
212
|
super
|
167
213
|
menu(:panel_menu).option_at 0, :close, icon: "remove"
|
168
|
-
panel_title "#{:
|
214
|
+
panel_title "#{assets[:model].model_icon.icon} #{LOCS[assets[:assoc][:name]]}"
|
169
215
|
end
|
170
216
|
|
171
217
|
def list_context query, handler
|
@@ -285,4 +331,3 @@ module Engine2
|
|
285
331
|
end
|
286
332
|
end
|
287
333
|
end
|
288
|
-
|
data/lib/engine2/action/save.rb
CHANGED
data/lib/engine2/action_node.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Engine2
|
5
|
-
|
6
5
|
class ActionNode < BasicObject
|
7
6
|
ACCESS_FORBIDDEN ||= ->h{false}
|
8
7
|
attr_reader :parent, :name, :number, :nodes, :recheck_access
|
@@ -201,7 +200,7 @@ module Engine2
|
|
201
200
|
true
|
202
201
|
end
|
203
202
|
|
204
|
-
::Kernel::puts "ACTION NODES: #{ActionNode.count}, Panels: #{panels},
|
203
|
+
::Kernel::puts "ACTION NODES: #{ActionNode.count}, Panels: #{panels}, Thefts: #{thefts}, Time: #{::Time.now - time}"
|
205
204
|
end
|
206
205
|
|
207
206
|
def p *args
|
@@ -209,7 +208,6 @@ module Engine2
|
|
209
208
|
end
|
210
209
|
end
|
211
210
|
|
212
|
-
|
213
211
|
class ActionNodeBundle
|
214
212
|
def initialize node, node_names
|
215
213
|
@node = node
|
@@ -220,4 +218,4 @@ module Engine2
|
|
220
218
|
@node_names.each{|an| @node[an].__send__(name, *args, &blk)}
|
221
219
|
end
|
222
220
|
end
|
223
|
-
end
|
221
|
+
end
|
data/lib/engine2/core.rb
CHANGED
@@ -126,6 +126,10 @@ class String
|
|
126
126
|
s
|
127
127
|
end
|
128
128
|
end
|
129
|
+
|
130
|
+
def escape_html
|
131
|
+
Rack::Utils.escape_html(self)
|
132
|
+
end
|
129
133
|
end
|
130
134
|
|
131
135
|
class Symbol
|
@@ -138,12 +142,18 @@ class Symbol
|
|
138
142
|
end
|
139
143
|
end
|
140
144
|
|
145
|
+
def loc
|
146
|
+
Engine2::LOCS[self]
|
147
|
+
end
|
148
|
+
|
141
149
|
def q col
|
142
150
|
col.qualify self
|
143
151
|
end
|
144
152
|
|
145
|
-
def
|
146
|
-
|
153
|
+
def html body = '', attrs = {}
|
154
|
+
element = self.to_s
|
155
|
+
attrs = attrs.map{|k, v| "#{k}=\"#{v}\""}.join(" ")
|
156
|
+
"<#{element} #{attrs}>#{body}</#{element}>"
|
147
157
|
end
|
148
158
|
end
|
149
159
|
|
@@ -174,7 +184,7 @@ class Sequel::Database
|
|
174
184
|
attr_accessor :models, :default_schema
|
175
185
|
|
176
186
|
def cache_file
|
177
|
-
"#{Engine2::SETTINGS.path_for(:db_path)}/#{opts[:orig_opts][:name]}.
|
187
|
+
"#{Engine2::SETTINGS.path_for(:db_path)}/#{opts[:orig_opts][:name]}.schema_cache"
|
178
188
|
end
|
179
189
|
|
180
190
|
def load_schema_cache_from_file
|
@@ -282,7 +292,7 @@ module E2Model
|
|
282
292
|
next if info[:primary_key] && !model.natural_key
|
283
293
|
|
284
294
|
value = values[name].to_s
|
285
|
-
value.strip! unless info[:dont_strip]
|
295
|
+
value.strip! unless value.frozen? || info[:dont_strip]
|
286
296
|
if value.empty?
|
287
297
|
if req = info[:required]
|
288
298
|
errors.add(name, req[:message]) if !req[:if] || req[:if].(self)
|
@@ -392,7 +402,6 @@ module E2Model
|
|
392
402
|
else
|
393
403
|
select(*pk.map{|k| model.table_name.q(k)})
|
394
404
|
end
|
395
|
-
|
396
405
|
end
|
397
406
|
|
398
407
|
def extract_select sel, al = nil, &blk
|
@@ -413,41 +422,41 @@ module E2Model
|
|
413
422
|
|
414
423
|
def setup_query fields
|
415
424
|
joins = {}
|
416
|
-
type_info = model.type_info
|
417
425
|
model_table_name = model.table_name
|
418
426
|
|
419
427
|
select = @opts[:select].map do |sel|
|
420
428
|
extract_select sel do |table, name, aliaz|
|
421
|
-
|
429
|
+
mdl = if table
|
422
430
|
if table == model_table_name
|
423
431
|
model
|
424
432
|
else
|
425
433
|
assoc = model.many_to_one_associations[table] || model.many_to_many_associations[table]
|
426
434
|
raise Engine2::E2Error.new("Association #{table} not found for model #{model}") unless assoc
|
427
435
|
assoc.associated_class
|
428
|
-
end
|
436
|
+
end
|
429
437
|
else
|
430
|
-
|
438
|
+
model
|
431
439
|
end
|
432
440
|
|
433
|
-
|
434
|
-
|
441
|
+
mdl_table_name = mdl.table_name
|
442
|
+
table ||= mdl_table_name
|
443
|
+
if mdl_table_name == model_table_name
|
435
444
|
fields << name
|
436
445
|
else
|
437
446
|
fields << table.q(name)
|
438
|
-
joins[
|
447
|
+
joins[mdl_table_name] ||= model.many_to_one_associations[table] || model.many_to_many_associations[table]
|
439
448
|
end
|
440
449
|
|
441
|
-
f_info =
|
442
|
-
raise Engine2::E2Error.new("Column #{name} not found for table #{table
|
450
|
+
f_info = mdl.type_info[name]
|
451
|
+
raise Engine2::E2Error.new("Column #{name} not found for table #{table}") unless f_info
|
443
452
|
if f_info[:dummy]
|
444
453
|
nil
|
445
454
|
else
|
446
|
-
qname =
|
447
|
-
if table
|
448
|
-
Sequel.alias_columns_in_joins ? qname.as(:"#{table}__#{name}") : qname
|
449
|
-
else
|
455
|
+
qname = mdl_table_name.q(name)
|
456
|
+
if table == model_table_name
|
450
457
|
qname
|
458
|
+
else
|
459
|
+
Sequel.alias_columns_in_joins ? qname.as(:"#{table}__#{name}") : qname
|
451
460
|
end
|
452
461
|
end
|
453
462
|
end
|
@@ -488,7 +497,6 @@ module Sequel
|
|
488
497
|
@error = error
|
489
498
|
end
|
490
499
|
end
|
491
|
-
|
492
500
|
end
|
493
501
|
|
494
502
|
module Engine2
|
@@ -501,7 +509,8 @@ module Engine2
|
|
501
509
|
model_path: 'models',
|
502
510
|
view_path: 'views',
|
503
511
|
asset_path: 'assets',
|
504
|
-
conf_path: 'conf'
|
512
|
+
conf_path: 'conf',
|
513
|
+
log_path: 'log'
|
505
514
|
}
|
506
515
|
|
507
516
|
def SETTINGS.path_for path
|
@@ -549,10 +558,10 @@ module Engine2
|
|
549
558
|
load "#{Engine2::SETTINGS[:app_path]}/boot.rb"
|
550
559
|
|
551
560
|
Sequel::DATABASES.each &:load_schema_cache_from_file
|
552
|
-
@model_boot_blk.() if @model_boot_blk
|
553
561
|
load 'engine2/models/Files.rb'
|
554
562
|
load 'engine2/models/UserInfo.rb'
|
555
563
|
Dir["#{Engine2::SETTINGS.path_for(:model_path)}/*"].each{|m| load m}
|
564
|
+
@model_boot_blk.() if @model_boot_blk
|
556
565
|
puts "MODELS: #{Sequel::DATABASES.reduce(0){|s, d|s + d.models.size}}, Time: #{Time.now - t}"
|
557
566
|
Sequel::DATABASES.each do |db|
|
558
567
|
db.dump_schema_cache_to_file
|
data/lib/engine2/handler.rb
CHANGED
@@ -119,16 +119,16 @@ module Engine2
|
|
119
119
|
slim name.to_sym
|
120
120
|
end
|
121
121
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
122
|
+
set :slim, pretty: !production?, sort_attrs: false
|
123
|
+
unless production? # use Engine2::SETTINGS[:reloading] ?
|
124
|
+
set :sessions, expire_after: 3600
|
125
|
+
# set :session_store, Rack::Session::Pool
|
126
|
+
end
|
126
127
|
|
127
128
|
helpers do
|
128
129
|
def find_template(views, name, engine, &block)
|
129
130
|
views.each{|v| super(v, name, engine, &block)}
|
130
131
|
end
|
131
132
|
end
|
132
|
-
|
133
133
|
end
|
134
134
|
end
|