engine2 1.0.8 → 1.0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|