engine2 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/engine2.rb +0 -2
- data/lib/engine2/action.rb +14 -13
- data/lib/engine2/core.rb +68 -57
- data/lib/engine2/handler.rb +4 -1
- data/lib/engine2/meta.rb +58 -11
- data/lib/engine2/meta/delete_meta.rb +2 -15
- data/lib/engine2/meta/infra_meta.rb +1 -2
- data/lib/engine2/meta/link_meta.rb +1 -0
- data/lib/engine2/meta/list_meta.rb +4 -3
- data/lib/engine2/meta/save_meta.rb +2 -15
- data/lib/engine2/meta/view_meta.rb +0 -1
- data/lib/engine2/model.rb +32 -22
- data/lib/engine2/scheme.rb +7 -15
- data/lib/engine2/type_info.rb +10 -13
- data/lib/engine2/version.rb +1 -1
- data/views/engine2.coffee +11 -7
- data/views/engine2actions.coffee +4 -1
- data/views/infra/inspect.slim +1 -1
- data/views/modals/close_m.slim +1 -1
- data/views/modals/confirm_m.slim +1 -1
- data/views/modals/empty_m.slim +1 -1
- data/views/modals/menu_m.slim +1 -1
- data/views/modals/yes_no_m.slim +1 -1
- data/views/panels/menu_m.slim +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a2ad0107737d0e5096b9a72b31743f01b8107ba
|
4
|
+
data.tar.gz: 6557952f0c927307bb297d71afc2cbb8086d3318
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 247de7a7bd6535a169b713cd08d1c9034d4e9de87301530986d9eae7b4ef98b4ceb9bff5610daf7ee66cc168c7f110dd585dd7db5691e07112f372c3345792d4
|
7
|
+
data.tar.gz: b41f9ea4e158dd174b4f71566f93d4fcc0f5bff6270f3885cc5f13e52b9e7fae0ba2f696273611453222bec33aed9f34556cd5a63c46f3a3f3dc8787e4ea7917
|
data/lib/engine2.rb
CHANGED
data/lib/engine2/action.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
module Engine2
|
4
|
+
|
4
5
|
class Action < BasicObject
|
5
6
|
ACCESS_FORBIDDEN ||= ->h{false}
|
6
7
|
attr_reader :parent, :name, :number, :actions, :recheck_access
|
7
|
-
attr_reader :meta_proc
|
8
|
+
attr_reader :meta_proc
|
8
9
|
|
9
10
|
class << self
|
10
11
|
attr_accessor :count
|
@@ -20,17 +21,7 @@ module Engine2
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def * &blk
|
23
|
-
if blk
|
24
|
-
@meta_proc = if meta_proc = @meta_proc
|
25
|
-
@meta_proc_chained = true
|
26
|
-
::Kernel::lambda do |obj|
|
27
|
-
obj.instance_eval(&meta_proc)
|
28
|
-
obj.instance_eval(&blk)
|
29
|
-
end
|
30
|
-
else
|
31
|
-
blk
|
32
|
-
end
|
33
|
-
end
|
24
|
+
@meta_proc = @meta_proc ? @meta_proc.chain(&blk) : blk if blk
|
34
25
|
@meta
|
35
26
|
end
|
36
27
|
|
@@ -74,6 +65,12 @@ module Engine2
|
|
74
65
|
end
|
75
66
|
end
|
76
67
|
|
68
|
+
def define_action_invoke name, meta_class = DummyMeta, assets = {}, &blk
|
69
|
+
define_action name, meta_class, assets do
|
70
|
+
self.*.define_singleton_method(:invoke, &blk)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
77
74
|
def undefine_action name
|
78
75
|
::Kernel.raise E2Error.new("No action #{name} defined") unless @actions[name]
|
79
76
|
@actions.delete(name)
|
@@ -163,7 +160,7 @@ module Engine2
|
|
163
160
|
model_name = model.name.to_sym
|
164
161
|
model.synchronize_type_info
|
165
162
|
model_actions[model_name] = action.to_a_rec{|a| !a.*.assets[:assoc]}
|
166
|
-
action.run_scheme(model_name) if SCHEMES
|
163
|
+
action.run_scheme(model_name) if SCHEMES[model_name, false]
|
167
164
|
false
|
168
165
|
else
|
169
166
|
true
|
@@ -216,6 +213,10 @@ module Engine2
|
|
216
213
|
end
|
217
214
|
::Kernel::puts "VERIFY #{::Time.now - t}"
|
218
215
|
end
|
216
|
+
|
217
|
+
def p *args
|
218
|
+
::Kernel::p *args
|
219
|
+
end
|
219
220
|
end
|
220
221
|
|
221
222
|
|
data/lib/engine2/core.rb
CHANGED
@@ -27,6 +27,14 @@ class Proc
|
|
27
27
|
loc = source_location
|
28
28
|
"\"#<Proc:#{loc.first[/\w+.rb/]}:#{loc.last}>\""
|
29
29
|
end
|
30
|
+
|
31
|
+
def chain &blk
|
32
|
+
proc = self
|
33
|
+
lambda do |obj|
|
34
|
+
obj.instance_eval(&proc)
|
35
|
+
obj.instance_eval(&blk)
|
36
|
+
end
|
37
|
+
end
|
30
38
|
end
|
31
39
|
|
32
40
|
class Hash
|
@@ -123,7 +131,7 @@ class Sequel::Database
|
|
123
131
|
attr_accessor :models, :default_schema
|
124
132
|
|
125
133
|
def cache_file
|
126
|
-
"#{
|
134
|
+
"#{Engine2::app}/#{opts[:orig_opts][:name]}.dump"
|
127
135
|
end
|
128
136
|
|
129
137
|
def load_schema_cache_from_file
|
@@ -236,7 +244,7 @@ module E2Model
|
|
236
244
|
else
|
237
245
|
info[:validations].each_pair do |validation, args|
|
238
246
|
validation_proc = Engine2::Validations[validation] || args[:lambda] # swap ?
|
239
|
-
raise "Validation not found for field '#{name}' of type #{validation}" unless validation_proc
|
247
|
+
raise E2Error.new("Validation not found for field '#{name}' of type #{validation}") unless validation_proc
|
240
248
|
if result = validation_proc.(self, name, info)
|
241
249
|
errors.add(name, result)
|
242
250
|
break
|
@@ -345,11 +353,7 @@ module E2Model
|
|
345
353
|
fields << name
|
346
354
|
else
|
347
355
|
fields << :"#{table}__#{name}"
|
348
|
-
|
349
|
-
unless assoc
|
350
|
-
# fail
|
351
|
-
end
|
352
|
-
joins[table] = assoc
|
356
|
+
joins[table] = model.many_to_one_associations[table]
|
353
357
|
end
|
354
358
|
|
355
359
|
if f_info[:dummy]
|
@@ -375,11 +379,9 @@ module E2Model
|
|
375
379
|
@opts[:select].compact!
|
376
380
|
|
377
381
|
joins.reduce(self) do |joined, (table, assoc)|
|
378
|
-
assoc = model.many_to_one_associations[table] # || model.one_to_one_associations[table]
|
379
382
|
m = Object.const_get(assoc[:class_name])
|
380
383
|
keys = assoc[:qualified_key]
|
381
|
-
|
382
|
-
joined.left_join(table, m.primary_keys.zip(keys))
|
384
|
+
joined.left_join(table, m.primary_keys.zip(keys.is_a?(Array) ? keys : [keys]))
|
383
385
|
end
|
384
386
|
end
|
385
387
|
|
@@ -433,65 +435,74 @@ module Engine2
|
|
433
435
|
PATH ||= File.expand_path('../..', File.dirname(__FILE__))
|
434
436
|
|
435
437
|
class << self
|
436
|
-
|
437
|
-
|
438
|
+
attr_reader :app, :reloading
|
439
|
+
attr_reader :core_loaded
|
438
440
|
|
439
|
-
|
441
|
+
def database name
|
442
|
+
Object.const_set(name, yield) unless Object.const_defined?(name)
|
443
|
+
end
|
440
444
|
|
441
|
-
|
442
|
-
|
443
|
-
|
445
|
+
def connect *args
|
446
|
+
db = Sequel.connect *args
|
447
|
+
db
|
448
|
+
end
|
444
449
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
db
|
449
|
-
end
|
450
|
+
def boot &blk
|
451
|
+
@boot_blk = blk
|
452
|
+
end
|
450
453
|
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
def DUMMYDB.synchronize *args;end
|
454
|
+
def model_boot &blk
|
455
|
+
@model_boot_blk = blk
|
456
|
+
end
|
455
457
|
|
456
|
-
|
457
|
-
|
458
|
-
|
458
|
+
def bootstrap_e2db
|
459
|
+
e2_db_file = (defined? JRUBY_VERSION) ? "jdbc:sqlite:#{@app}/engine2.db" : "sqlite://#{@app}/engine2.db"
|
460
|
+
Engine2.const_set :E2DB, connect(e2_db_file, loggers: [Logger.new($stdout)], convert_types: false, name: :engine2)
|
461
|
+
Engine2.const_set :DUMMYDB, Sequel::Database.new(uri: 'dummy')
|
462
|
+
def DUMMYDB.synchronize *args;end
|
463
|
+
end
|
459
464
|
|
460
|
-
|
461
|
-
|
462
|
-
|
465
|
+
def reload
|
466
|
+
@core_loaded = true
|
467
|
+
t = Time.now
|
468
|
+
Action.count = 0
|
469
|
+
SCHEMES.user.clear
|
470
|
+
|
471
|
+
Sequel::DATABASES.each do |db|
|
472
|
+
db.models.each{|n, m| Object.send(:remove_const, n) if Object.const_defined?(n)} unless db == E2DB || db == DUMMYDB
|
473
|
+
end
|
463
474
|
|
464
|
-
|
465
|
-
require 'engine2/pre_bootstrap'
|
466
|
-
t = Time.now
|
467
|
-
Action.count = 0
|
468
|
-
SCHEMES.clear
|
475
|
+
load "#{app}/boot.rb"
|
469
476
|
|
470
|
-
|
471
|
-
|
472
|
-
|
477
|
+
Sequel::DATABASES.each &:load_schema_cache_from_file
|
478
|
+
@model_boot_blk.() if @model_boot_blk
|
479
|
+
load 'engine2/models/Files.rb'
|
480
|
+
load 'engine2/models/UserInfo.rb'
|
481
|
+
Dir["#{app}/models/*"].each{|m| load m}
|
482
|
+
puts "MODELS: #{Sequel::DATABASES.reduce(0){|s, d|s + d.models.size}}, Time: #{Time.now - t}"
|
483
|
+
Sequel::DATABASES.each &:dump_schema_cache_to_file
|
473
484
|
|
474
|
-
|
485
|
+
Engine2.send(:remove_const, :ROOT) if defined? ROOT
|
486
|
+
Engine2.const_set(:ROOT, Action.new(nil, :api, DummyMeta, {}))
|
475
487
|
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
Dir["#{app}/models/*"].each{|m| load m}
|
481
|
-
puts "MODELS, Time: #{Time.now - t}"
|
482
|
-
Sequel::DATABASES.each &:dump_schema_cache_to_file
|
488
|
+
@boot_blk.(ROOT)
|
489
|
+
ROOT.setup_action_tree
|
490
|
+
puts "BOOTSTRAP #{app}, Time: #{Time.new - t}"
|
491
|
+
end
|
483
492
|
|
484
|
-
|
485
|
-
|
486
|
-
|
493
|
+
def bootstrap app, opts = {}
|
494
|
+
@app = app
|
495
|
+
@reloading = opts[:reloading]
|
496
|
+
bootstrap_e2db
|
487
497
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
require 'engine2/post_bootstrap'
|
498
|
+
require 'engine2/pre_bootstrap'
|
499
|
+
reload
|
500
|
+
require 'engine2/post_bootstrap'
|
501
|
+
end
|
493
502
|
end
|
494
503
|
|
504
|
+
@core_loaded = false
|
505
|
+
|
495
506
|
class E2Error < RuntimeError
|
496
507
|
def initialize msg
|
497
508
|
super
|
@@ -534,9 +545,9 @@ module Engine2
|
|
534
545
|
option name, properties, index, &blk
|
535
546
|
end
|
536
547
|
|
537
|
-
def option_index iname
|
548
|
+
def option_index iname, raise = true
|
538
549
|
index = @entries.index{|e| (e.is_a?(MenuBuilder) ? e.name : e[:name]) == iname}
|
539
|
-
raise E2Error.new("No menu option #{iname} found")
|
550
|
+
raise E2Error.new("No menu option #{iname} found") if !index && raise
|
540
551
|
index
|
541
552
|
end
|
542
553
|
|
data/lib/engine2/handler.rb
CHANGED
@@ -113,7 +113,10 @@ module Engine2
|
|
113
113
|
get '/*' do |name|
|
114
114
|
headers 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0'
|
115
115
|
if name.empty?
|
116
|
-
|
116
|
+
if settings.environment == :development
|
117
|
+
load('engine2.rb') if Engine2::reloading
|
118
|
+
Engine2::reload
|
119
|
+
end
|
117
120
|
name = 'index'
|
118
121
|
end
|
119
122
|
slim name.to_sym
|
data/lib/engine2/meta.rb
CHANGED
@@ -140,13 +140,13 @@ module Engine2
|
|
140
140
|
|
141
141
|
class DummyMeta < Meta
|
142
142
|
meta_type :dummy
|
143
|
-
|
144
|
-
# def invoke handler
|
145
|
-
# {}
|
146
|
-
# end
|
147
143
|
end
|
148
144
|
|
149
145
|
module MetaAPISupport
|
146
|
+
def reload_routes!
|
147
|
+
@meta[:reload_routes] = true
|
148
|
+
end
|
149
|
+
|
150
150
|
def info
|
151
151
|
@meta[:info] ||= {}
|
152
152
|
end
|
@@ -166,6 +166,10 @@ module Engine2
|
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
|
+
def loc! hash
|
170
|
+
hash.each{|k, v| info! k, loc: v}
|
171
|
+
end
|
172
|
+
|
169
173
|
def decorate list
|
170
174
|
list.each do |f|
|
171
175
|
m = (info[f] ||= {})
|
@@ -420,13 +424,10 @@ module Engine2
|
|
420
424
|
panel_panel_template 'menu_m' unless panel[:panel_template] == false
|
421
425
|
# modal_action false if panel[:panel_template] == false
|
422
426
|
panel_class '' unless panel[:class]
|
427
|
+
footer true unless panel[:footer] == false
|
423
428
|
end
|
424
429
|
end
|
425
430
|
|
426
|
-
def glyphicon name
|
427
|
-
"<span class='glyphicon glyphicon-#{name}'></span>"
|
428
|
-
end
|
429
|
-
|
430
431
|
def panel
|
431
432
|
@meta[:panel] ||= {}
|
432
433
|
end
|
@@ -450,6 +451,10 @@ module Engine2
|
|
450
451
|
def panel_title tle
|
451
452
|
panel[:title] = tle
|
452
453
|
end
|
454
|
+
|
455
|
+
def footer ftr
|
456
|
+
panel[:footer] = ftr
|
457
|
+
end
|
453
458
|
end
|
454
459
|
|
455
460
|
class MenuMeta < Meta
|
@@ -543,16 +548,14 @@ module Engine2
|
|
543
548
|
panel_template 'scaffold/list'
|
544
549
|
panel_panel_template 'panels/menu_m' unless action.parent.*.assets[:model]
|
545
550
|
search_template 'scaffold/search'
|
546
|
-
panel_title "#{
|
551
|
+
panel_title "#{:list.icon} #{LOCS[assets[:model].name.to_sym]}"
|
547
552
|
menu(:panel_menu).option :cancel, icon: "remove"
|
548
553
|
menu :menu do
|
549
554
|
properties break: 2, group_class: "btn-group-xs"
|
550
555
|
option :search_toggle, icon: "search", show: "action.meta.search_fields", class: "action.ui_state.search_active && 'active'", button_loc: false
|
551
|
-
|
552
556
|
# divider
|
553
557
|
option :refresh, icon: "refresh", button_loc: false
|
554
558
|
option :default_order, icon: "signal", button_loc: false
|
555
|
-
option :select_toggle, icon: "check", enabled: "action.meta.config.selectable", button_loc: false
|
556
559
|
divider
|
557
560
|
option :debug_info, icon: "list-alt" do
|
558
561
|
option :show_meta, icon: "eye-open"
|
@@ -566,6 +569,13 @@ module Engine2
|
|
566
569
|
@meta[:state] = [:query, :ui_state]
|
567
570
|
end
|
568
571
|
|
572
|
+
def select_toggle_menu
|
573
|
+
m = menu :menu
|
574
|
+
unless m.option_index(:select_toggle, false)
|
575
|
+
m.option_after :default_order, :select_toggle, icon: "check", enabled: "action.meta.config.selectable", button_loc: false
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
569
579
|
def post_run
|
570
580
|
unless panel[:class]
|
571
581
|
panel_class case @meta[:fields].size
|
@@ -666,6 +676,10 @@ module Engine2
|
|
666
676
|
include MetaModelSupport
|
667
677
|
attr_reader :validations
|
668
678
|
|
679
|
+
def self.included meta
|
680
|
+
meta.http_method :post
|
681
|
+
end
|
682
|
+
|
669
683
|
def validate_fields *fields
|
670
684
|
if fields.empty?
|
671
685
|
@validate_fields
|
@@ -736,6 +750,10 @@ module Engine2
|
|
736
750
|
module MetaViewSupport
|
737
751
|
include MetaModelSupport, MetaAPISupport, MetaTabSupport, MetaPanelSupport, MetaMenuSupport
|
738
752
|
|
753
|
+
def self.included meta
|
754
|
+
meta.meta_type :view
|
755
|
+
end
|
756
|
+
|
739
757
|
def pre_run
|
740
758
|
super
|
741
759
|
panel_template 'scaffold/view'
|
@@ -761,6 +779,35 @@ module Engine2
|
|
761
779
|
end
|
762
780
|
end
|
763
781
|
|
782
|
+
module MetaDeleteSupport
|
783
|
+
include MetaModelSupport
|
784
|
+
|
785
|
+
def self.included meta
|
786
|
+
meta.http_method :delete
|
787
|
+
meta.meta_type :delete
|
788
|
+
end
|
789
|
+
|
790
|
+
def pre_run
|
791
|
+
super
|
792
|
+
action.parent.parent.*.menu(:item_menu).option :confirm_delete, icon: "trash", show: "action.selected_size() == 0", button_loc: false
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
module MetaBulkDeleteSupport
|
797
|
+
include MetaModelSupport
|
798
|
+
|
799
|
+
def self.included meta
|
800
|
+
meta.http_method :delete
|
801
|
+
meta.meta_type :bulk_delete
|
802
|
+
end
|
803
|
+
|
804
|
+
def pre_run
|
805
|
+
super
|
806
|
+
action.parent.parent.*.select_toggle_menu
|
807
|
+
action.parent.parent.*.menu(:menu).option_after :default_order, :confirm_bulk_delete, icon: "trash", show: "action.selected_size() > 0"
|
808
|
+
end
|
809
|
+
end
|
810
|
+
|
764
811
|
(FormRendererPostProcessors ||= {}).merge!(
|
765
812
|
boolean: lambda{|meta, field, info|
|
766
813
|
meta.info[field][:render].merge! true_value: info[:true_value], false_value: info[:false_value]
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module Engine2
|
4
4
|
class DeleteMetaBase < Meta
|
5
|
-
include MetaModelSupport
|
6
5
|
|
7
6
|
def invoke_delete_db handler, ids
|
8
7
|
begin
|
@@ -40,13 +39,7 @@ module Engine2
|
|
40
39
|
end
|
41
40
|
|
42
41
|
class DeleteMeta < DeleteMetaBase
|
43
|
-
|
44
|
-
meta_type :delete
|
45
|
-
|
46
|
-
def pre_run
|
47
|
-
super
|
48
|
-
action.parent.parent.*.menu(:item_menu).option :confirm_delete, icon: "trash", show: "action.selected_size() == 0", button_loc: false
|
49
|
-
end
|
42
|
+
include MetaDeleteSupport
|
50
43
|
|
51
44
|
def invoke handler
|
52
45
|
handler.permit id = handler.params[:id]
|
@@ -55,13 +48,7 @@ module Engine2
|
|
55
48
|
end
|
56
49
|
|
57
50
|
class BulkDeleteMeta < DeleteMetaBase
|
58
|
-
|
59
|
-
meta_type :bulk_delete
|
60
|
-
|
61
|
-
def pre_run
|
62
|
-
super
|
63
|
-
action.parent.parent.*.menu(:menu).option_after :default_order, :confirm_bulk_delete, icon: "trash", show: "action.selected_size() > 0"
|
64
|
-
end
|
51
|
+
include MetaBulkDeleteSupport
|
65
52
|
|
66
53
|
def invoke handler
|
67
54
|
ids = handler.param_to_json(:ids)
|
@@ -12,7 +12,7 @@ module Engine2
|
|
12
12
|
option :inspect_modal, icon: :wrench, button_loc: false # , show: "action.logged_on"
|
13
13
|
|
14
14
|
option :logout_form, icon: :"log-out" # , show: "action.logged_on"
|
15
|
-
option :login_form, icon: :"log-in" # , show: "!action.logged_on"
|
15
|
+
option :login_form, icon: :"log-in", disabled: 'action.action_pending' # , show: "!action.logged_on"
|
16
16
|
end
|
17
17
|
|
18
18
|
@meta_type = :infra
|
@@ -249,7 +249,6 @@ module Engine2
|
|
249
249
|
|
250
250
|
class LoginMeta < Meta
|
251
251
|
include MetaApproveSupport
|
252
|
-
http_method :post
|
253
252
|
meta_type :login
|
254
253
|
|
255
254
|
def after_approve handler, record
|
@@ -113,6 +113,7 @@ module Engine2
|
|
113
113
|
|
114
114
|
def pre_run
|
115
115
|
super
|
116
|
+
action.parent.parent.*.select_toggle_menu
|
116
117
|
action.parent.parent.*.menu(:menu).option_after :default_order, :confirm_bulk_unlink, icon: "minus", show: "action.selected_size() > 0", button_loc: false
|
117
118
|
end
|
118
119
|
|
@@ -155,7 +155,7 @@ module Engine2
|
|
155
155
|
meta_type :star_to_many_list
|
156
156
|
def pre_run
|
157
157
|
super
|
158
|
-
panel_title "#{
|
158
|
+
panel_title "#{:list.icon} #{LOCS[assets[:assoc][:name]]}"
|
159
159
|
end
|
160
160
|
|
161
161
|
# def decode_panel_title handler
|
@@ -177,10 +177,11 @@ module Engine2
|
|
177
177
|
handler.permit parent = handler.params[:parent_id]
|
178
178
|
model = assets[:model]
|
179
179
|
assoc = assets[:assoc]
|
180
|
+
parent_keys = split_keys(parent)
|
180
181
|
case assoc[:type]
|
181
182
|
when :one_to_many
|
182
183
|
keys = assoc[:keys]
|
183
|
-
condition =
|
184
|
+
condition = parent_keys.all?(&:empty?) ? false : Hash[keys.map{|k| k.qualify(model.table_name)}.zip(parent_keys)]
|
184
185
|
if handler.params[:negate]
|
185
186
|
query = query.exclude(condition)
|
186
187
|
query = query.or(Hash[keys.zip([nil])]) if keys.all?{|k|model.db_schema[k][:allow_null] == true} # type_info[:required] ?
|
@@ -194,7 +195,7 @@ module Engine2
|
|
194
195
|
l_keys = assoc[:left_keys].map{|k| k.qualify(j_table)}
|
195
196
|
r_keys = assoc[:right_keys].map{|k| k.qualify(j_table)}
|
196
197
|
r_keys_vals = Hash[r_keys.zip(q_pk)]
|
197
|
-
l_keys_vals =
|
198
|
+
l_keys_vals = parent_keys.all?(&:empty?) ? false : Hash[l_keys.zip(parent_keys)]
|
198
199
|
|
199
200
|
if handler.params[:negate]
|
200
201
|
query.exclude(model.db[j_table].select(nil).where(r_keys_vals, l_keys_vals).exists)
|
@@ -4,7 +4,6 @@ module Engine2
|
|
4
4
|
|
5
5
|
class SaveMeta < Meta
|
6
6
|
include MetaApproveSupport
|
7
|
-
http_method :post
|
8
7
|
|
9
8
|
def validate_and_approve handler, record, json
|
10
9
|
record.skip_save_refresh = true
|
@@ -28,7 +27,7 @@ module Engine2
|
|
28
27
|
end
|
29
28
|
|
30
29
|
class InsertMeta < SaveMeta
|
31
|
-
meta_type :
|
30
|
+
meta_type :approve
|
32
31
|
def allocate_record handler, json
|
33
32
|
record = super(handler, json)
|
34
33
|
record.instance_variable_set(:"@new", true)
|
@@ -40,7 +39,7 @@ module Engine2
|
|
40
39
|
end
|
41
40
|
|
42
41
|
class UpdateMeta < SaveMeta
|
43
|
-
meta_type :
|
42
|
+
meta_type :approve
|
44
43
|
def allocate_record handler, json
|
45
44
|
record = super(handler, json)
|
46
45
|
model = assets[:model]
|
@@ -48,16 +47,4 @@ module Engine2
|
|
48
47
|
record
|
49
48
|
end
|
50
49
|
end
|
51
|
-
|
52
|
-
module TimeStampMeta
|
53
|
-
def before_approve handler, record
|
54
|
-
super
|
55
|
-
puts "before approve"
|
56
|
-
end
|
57
|
-
|
58
|
-
def after_approve handler, record
|
59
|
-
super
|
60
|
-
puts "after approve"
|
61
|
-
end
|
62
|
-
end
|
63
50
|
end
|
data/lib/engine2/model.rb
CHANGED
@@ -7,28 +7,25 @@ module Engine2
|
|
7
7
|
attr_reader :before_save_processors, :after_save_processors, :before_destroy_processors, :after_destroy_processors
|
8
8
|
attr_reader :validation_in_transaction
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@after_destroy_processors = nil
|
28
|
-
@type_info_synchronized = nil
|
29
|
-
end
|
30
|
-
cls.setup_schema
|
10
|
+
def self.extended cls
|
11
|
+
models = cls.db.models
|
12
|
+
raise E2Error.new("Model '#{cls.name}' already defined") if models[cls.name.to_sym]
|
13
|
+
models[cls.name.to_sym] = cls
|
14
|
+
|
15
|
+
cls.instance_eval do
|
16
|
+
@many_to_one_associations = association_reflections.select{|n, a| a[:type] == :many_to_one}
|
17
|
+
@one_to_many_associations = association_reflections.select{|n, a| a[:type] == :one_to_many}
|
18
|
+
@many_to_many_associations = association_reflections.select{|n, a| a[:type] == :many_to_many}
|
19
|
+
# @one_to_one_associations = association_reflections.select{|n, a| a[:type] == :one_to_one}
|
20
|
+
@validation_in_transaction = nil
|
21
|
+
@before_save_processors = nil
|
22
|
+
@after_save_processors = nil
|
23
|
+
@around_save_processors = nil
|
24
|
+
@before_destroy_processors = nil
|
25
|
+
@after_destroy_processors = nil
|
26
|
+
@type_info_synchronized = nil
|
31
27
|
end
|
28
|
+
cls.setup_schema
|
32
29
|
end
|
33
30
|
|
34
31
|
def install_processors processors
|
@@ -111,6 +108,7 @@ module Engine2
|
|
111
108
|
|
112
109
|
def synchronize_type_info
|
113
110
|
resolve_dependencies
|
111
|
+
verify_associations
|
114
112
|
@before_save_processors = install_processors(BeforeSaveProcessors)
|
115
113
|
@after_save_processors = install_processors(AfterSaveProcessors)
|
116
114
|
@around_save_processors = {}
|
@@ -119,6 +117,18 @@ module Engine2
|
|
119
117
|
@type_info_synchronized = true
|
120
118
|
end
|
121
119
|
|
120
|
+
def verify_associations
|
121
|
+
one_to_many_associations.each do |name, assoc|
|
122
|
+
other = Object.const_get(assoc[:class_name])
|
123
|
+
other_type_info = other.type_info
|
124
|
+
if other_keys = assoc[:keys]
|
125
|
+
other_keys.each do |key|
|
126
|
+
raise E2Error.new("No key '#{key}' found in model '#{other}' being related from #{self}") unless other_type_info[key]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
122
132
|
def resolve_dependencies
|
123
133
|
resolved = {}
|
124
134
|
@type_info.each_pair do |name, info|
|
@@ -133,7 +143,7 @@ module Engine2
|
|
133
143
|
deps = @type_info[name][:depends]
|
134
144
|
deps.each do |e|
|
135
145
|
if !resolved[e]
|
136
|
-
raise "Circular dependency for field '#{name}' in model '#{self}'" if seen.include?(e)
|
146
|
+
raise E2Error.new("Circular dependency for field '#{name}' in model '#{self}'") if seen.include?(e)
|
137
147
|
resolve_dependency(e, resolved, seen)
|
138
148
|
end
|
139
149
|
end if deps
|
data/lib/engine2/scheme.rb
CHANGED
@@ -6,31 +6,23 @@ module Engine2
|
|
6
6
|
VIEW ||= {view: true}.freeze
|
7
7
|
LINK ||= {star_to_many_link: true, view: true, star_to_many_unlink: true}.freeze # star_to_many_bulk_unlink: true
|
8
8
|
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :builtin, :user
|
10
10
|
def initialize
|
11
11
|
@builtin = {}
|
12
|
-
@
|
12
|
+
@user = {}
|
13
13
|
end
|
14
14
|
|
15
15
|
def define_scheme name, &blk
|
16
|
-
schemes = Engine2::
|
17
|
-
raise "Scheme '#{name}' already defined" if schemes[name]
|
16
|
+
schemes = Engine2::core_loaded ? @user : @builtin
|
17
|
+
raise E2Error.new("Scheme '#{name}' already defined") if schemes[name]
|
18
18
|
schemes[name] = blk
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def [] name
|
26
|
-
scheme = @schemes[name]
|
27
|
-
raise E2Error.new("Scheme #{name} not found") unless scheme
|
21
|
+
def [] name, raise = true
|
22
|
+
scheme = @builtin[name] || @user[name]
|
23
|
+
raise E2Error.new("Scheme #{name} not found") if !scheme && raise
|
28
24
|
scheme
|
29
25
|
end
|
30
|
-
|
31
|
-
def merge!
|
32
|
-
@schemes.merge!(@builtin){|n| raise E2Error.new("Scheme collision: #{n}")}
|
33
|
-
end
|
34
26
|
end
|
35
27
|
|
36
28
|
SCHEMES ||= Schemes.new
|
data/lib/engine2/type_info.rb
CHANGED
@@ -209,8 +209,8 @@ module Engine2
|
|
209
209
|
info[:multiple] = multiple
|
210
210
|
info[:table] = table
|
211
211
|
info[:store] = store
|
212
|
-
info[:store][:upload] ||= "#{
|
213
|
-
info[:store][:files] ||= "#{
|
212
|
+
info[:store][:upload] ||= "#{Engine2::app}/store/upload"
|
213
|
+
info[:store][:files] ||= "#{Engine2::app}/store/files"
|
214
214
|
info[:transaction] = true
|
215
215
|
end
|
216
216
|
end
|
@@ -265,9 +265,8 @@ module Engine2
|
|
265
265
|
end
|
266
266
|
|
267
267
|
def foreign_blob_store_field assoc_name, name, name_field, mime_field
|
268
|
-
assoc = @model.
|
269
|
-
raise E2Error.new("
|
270
|
-
raise E2Error.new("Association '#{assoc_name}' in model '#{@mode}' is not of type many_to_one") unless assoc[:type] == :many_to_one
|
268
|
+
assoc = @model.many_to_one_associations[assoc_name]
|
269
|
+
raise E2Error.new("'many_to_one' association '#{assoc_name}' not found for model '#{@model}'") unless assoc
|
271
270
|
define_field :"#{assoc[:key]}_blob", :foreign_blob_store do |info|
|
272
271
|
info[:assoc_name] = assoc_name
|
273
272
|
info[:bytes_field] = name
|
@@ -278,9 +277,8 @@ module Engine2
|
|
278
277
|
end
|
279
278
|
|
280
279
|
def many_to_one_field assoc_name
|
281
|
-
assoc = @model.
|
282
|
-
raise E2Error.new("
|
283
|
-
raise E2Error.new("Association '#{assoc_name}' in model '#{@mode}' is not of type many_to_one") unless assoc[:type] == :many_to_one
|
280
|
+
assoc = @model.many_to_one_associations[assoc_name]
|
281
|
+
raise E2Error.new("'many_to_one' association '#{assoc_name}' not found for model '#{@model}'") unless assoc
|
284
282
|
keys = assoc[:keys]
|
285
283
|
modify_field keys.first do |info|
|
286
284
|
info[:type] = :many_to_one
|
@@ -290,9 +288,8 @@ module Engine2
|
|
290
288
|
end
|
291
289
|
|
292
290
|
def star_to_many_field assoc_name
|
293
|
-
assoc = @model.
|
294
|
-
raise E2Error.new("
|
295
|
-
raise E2Error.new("Association '#{assoc_name}' in model '#{@model}' is not of type *_to_many") unless [:one_to_many, :many_to_many].include?(assoc[:type])
|
291
|
+
assoc = @model.one_to_many_associations[assoc_name] || @model.many_to_many_associations[assoc_name]
|
292
|
+
raise E2Error.new("'*_to_many' association '#{assoc_name}' not found for model '#{@model}'") unless assoc
|
296
293
|
define_field assoc_name, :string do |info|
|
297
294
|
info[:type] = :star_to_many_field
|
298
295
|
info[:keys] = assoc[:keys]
|
@@ -309,7 +306,7 @@ module Engine2
|
|
309
306
|
# list.map{|k, v| {id: k, value: v}}
|
310
307
|
list.to_a
|
311
308
|
else
|
312
|
-
raise E2Error.new("type not supported for list_select modifier for field #{name}")
|
309
|
+
raise E2Error.new("type '#{list.class}' not supported for list_select modifier for field #{name}")
|
313
310
|
end
|
314
311
|
info[:validations][:list_select] = true
|
315
312
|
end
|
@@ -317,7 +314,7 @@ module Engine2
|
|
317
314
|
|
318
315
|
def decode name, dinfo = {form: {scaffold: true}, search: {scaffold: true}}
|
319
316
|
modify_field name do |info|
|
320
|
-
raise E2Error.new("Field type of #{name} needs to be
|
317
|
+
raise E2Error.new("Field type of '#{name}' in model '#{@model}' needs to be 'many_to_one'") unless info[:type] == :many_to_one
|
321
318
|
dec = info[:decode] ||= {}
|
322
319
|
dec[:search].clear if dinfo[:search] && dec[:search]
|
323
320
|
dec[:form].clear if dinfo[:form] && dec[:form]
|
data/lib/engine2/version.rb
CHANGED
data/views/engine2.coffee
CHANGED
@@ -279,14 +279,14 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
|
|
279
279
|
error: (title, msg, html) ->
|
280
280
|
body = if html then msg else "<div class='alert alert-danger'>#{msg}</div>"
|
281
281
|
clazz = if html then "modal-huge" else "modal-large"
|
282
|
-
@show meta: panel: (panel_template: "close_m", template_string: body, title: title, class: clazz) # message: msg,
|
282
|
+
@show meta: panel: (panel_template: "close_m", template_string: body, title: title, class: clazz, footer: true) # message: msg,
|
283
283
|
|
284
284
|
confirm: (title, msg, action) ->
|
285
285
|
body = "<div class='alert alert-warning'>#{msg}</div>"
|
286
286
|
clazz = "modal-large"
|
287
287
|
@show
|
288
288
|
confirm: action,
|
289
|
-
meta: panel: (panel_template: "confirm_m", template_string: body, title: title, class: clazz) # message: msg,
|
289
|
+
meta: panel: (panel_template: "confirm_m", template_string: body, title: title, class: clazz, footer: true) # message: msg,
|
290
290
|
|
291
291
|
.directive 'e2Modal', ($e2Modal) ->
|
292
292
|
restrict: 'E'
|
@@ -301,7 +301,7 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
|
|
301
301
|
return if ev.defaultPrevented
|
302
302
|
ev.preventDefault()
|
303
303
|
|
304
|
-
panel = panel_template: attrs.panelTemplate, title: attrs.title, class: attrs.clazz
|
304
|
+
panel = panel_template: attrs.panelTemplate, title: attrs.title, class: attrs.clazz, footer: true
|
305
305
|
if obody then panel.template_string = obody.outerHTML else panel.template = attrs.template
|
306
306
|
action = meta: (panel: panel), scope: -> scope
|
307
307
|
_.assign(action, args)
|
@@ -386,12 +386,16 @@ angular.module('Engine2', ['ngRoute', 'ngSanitize', 'ngAnimate', 'ngCookies', 'm
|
|
386
386
|
selection = scope.action.selection
|
387
387
|
out = ''
|
388
388
|
_.each scope.action.entries, (e, i) ->
|
389
|
-
out += if selection then "<tr ng-class='action.selected_class(#{i})' class='tr_hover' ng-click='action.select(#{i}, $event)'>" else
|
389
|
+
out += if selection then "<tr ng-class='action.selected_class(#{i})' class='tr_hover' ng-click='action.select(#{i}, $event)'>" else
|
390
|
+
row_cls = e.$row_info?.class
|
391
|
+
if row_cls then "<tr class=\"#{row_cls}\">" else "<tr>"
|
390
392
|
out += "<td>"
|
391
|
-
out += "<div e2-button-set='action.meta.menus.item_menu' index='#{i}'></div>" if meta.config.show_item_menu
|
393
|
+
out += "<div e2-button-set='action.meta.menus.item_menu' index='#{i}'></div>" if meta.config.show_item_menu
|
392
394
|
out += "</td>"
|
393
|
-
|
394
|
-
|
395
|
+
_.each meta.fields, (f) ->
|
396
|
+
out += if col_cls = meta.info[f].column_class then "<td class='#{col_cls}'>" else "<td>"
|
397
|
+
out += scope.action.list_cell(e, f) ? ''
|
398
|
+
out += "</td>"
|
395
399
|
out += "</tr>"
|
396
400
|
|
397
401
|
elem.empty()
|
data/views/engine2actions.coffee
CHANGED
@@ -128,9 +128,11 @@ angular.module('Engine2')
|
|
128
128
|
|
129
129
|
pre_invoke: ->
|
130
130
|
@parent().action_pending = true
|
131
|
+
@action_pending = true
|
131
132
|
# @parent().parent().action_pending = true if @parent().parent()
|
132
133
|
post_invoke: ->
|
133
134
|
delete @parent().action_pending # = false
|
135
|
+
delete @action_pending
|
134
136
|
# @parent().parent().action_pending = false if @parent().parent()
|
135
137
|
invoke: ->
|
136
138
|
args = arguments
|
@@ -282,7 +284,7 @@ angular.module('Engine2')
|
|
282
284
|
|
283
285
|
traverse: (routes) ->
|
284
286
|
menu_tmpl = _.template("<li><a href='{{href}}'>{{icon}}{{aicon}} {{loc}}</a></li>")
|
285
|
-
menu_sub_tmpl = _.template("<li e2-drop-down='{{dropdown}}'><a href='javascript://'>{{icon}}{{aicon}}{{loc}}<span class='caret'></span></a></li>")
|
287
|
+
menu_sub_tmpl = _.template("<li e2-drop-down='{{dropdown}}'><a href='javascript://'>{{icon}}{{aicon}} {{loc}}<span class='caret'></span></a></li>")
|
286
288
|
out = routes.map (route, i) ->
|
287
289
|
if route.menu
|
288
290
|
menu_sub_tmpl
|
@@ -565,6 +567,7 @@ angular.module('Engine2')
|
|
565
567
|
super()
|
566
568
|
@decode_field = @scope().f
|
567
569
|
@dinfo = @parentp().meta.info[@decode_field]
|
570
|
+
throw "Primary and foreign key list lengths dont match: [#{@meta.primary_fields}] and [#{@dinfo.fields}]" unless @meta.primary_fields.length == @dinfo.fields.length
|
568
571
|
@scope().$on "search_reset", => @clean()
|
569
572
|
|
570
573
|
if_fk_values: (f) ->
|
data/views/infra/inspect.slim
CHANGED
data/views/modals/close_m.slim
CHANGED
data/views/modals/confirm_m.slim
CHANGED
data/views/modals/empty_m.slim
CHANGED
data/views/modals/menu_m.slim
CHANGED
data/views/modals/yes_no_m.slim
CHANGED
data/views/panels/menu_m.slim
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
h4.modal-title ng-bind-html="action.meta.panel.title"
|
4
4
|
.panel-body
|
5
5
|
| modal-content-to-replace
|
6
|
-
.panel-footer
|
6
|
+
.panel-footer ng-if="::action.meta.panel.footer"
|
7
7
|
// .loader.pull-left: img src="img/ajax-loader.gif"
|
8
8
|
div e2-button-set="action.meta.menus.panel_menu"
|
9
9
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: engine2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lopex
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|