engine2 1.0.8 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -3
  3. data/app/actions.coffee +87 -50
  4. data/app/app.css +2 -1
  5. data/app/engine2.coffee +37 -19
  6. data/app/modal.coffee +8 -3
  7. data/bower.json +3 -2
  8. data/conf/message.yaml +3 -0
  9. data/conf/message_pl.yaml +5 -2
  10. data/config.coffee +16 -15
  11. data/engine2.gemspec +1 -1
  12. data/lib/engine2/action.rb +51 -23
  13. data/lib/engine2/action/array.rb +94 -1
  14. data/lib/engine2/action/decode.rb +29 -3
  15. data/lib/engine2/action/delete.rb +1 -2
  16. data/lib/engine2/action/infra.rb +5 -4
  17. data/lib/engine2/action/list.rb +70 -25
  18. data/lib/engine2/action/save.rb +0 -2
  19. data/lib/engine2/action_node.rb +2 -4
  20. data/lib/engine2/core.rb +30 -21
  21. data/lib/engine2/handler.rb +5 -5
  22. data/lib/engine2/model.rb +18 -9
  23. data/lib/engine2/models/Files.rb +2 -0
  24. data/lib/engine2/scheme.rb +1 -6
  25. data/lib/engine2/templates.rb +32 -6
  26. data/lib/engine2/type_info.rb +9 -5
  27. data/lib/engine2/version.rb +1 -1
  28. data/package.json +9 -8
  29. data/views/fields/checkbox_button.slim +6 -0
  30. data/views/fields/checkbox_buttons.slim +1 -1
  31. data/views/fields/list_mbuttons.slim +9 -0
  32. data/views/fields/list_mbuttons_opt.slim +11 -0
  33. data/views/fields/list_mselect.slim +12 -0
  34. data/views/fields/scaffold.slim +1 -1
  35. data/views/fields/typeahead_picker.slim +8 -5
  36. data/views/infra/inspect.slim +19 -16
  37. data/views/scaffold/fields.slim +3 -1
  38. data/views/scaffold/search.slim +2 -2
  39. data/views/scaffold/search_collapse.slim +2 -2
  40. data/views/scaffold/search_tabs.slim +2 -2
  41. data/views/search_fields/date.slim +20 -0
  42. data/views/search_fields/list_mbuttons.slim +12 -0
  43. data/views/search_fields/typeahead_picker.slim +4 -3
  44. metadata +11 -5
@@ -97,11 +97,16 @@ angular.module('Engine2')
97
97
  modal.show()
98
98
  modal
99
99
 
100
- error: (title, msg, html) ->
101
- body = if html then msg else "<div class='alert alert-danger'>#{msg}</div>"
102
- clazz = if html then "modal-huge" else "modal-large"
100
+ show_modal: (title, msg, options = {html: false, alert_class: 'alert-danger', modal_class: 'modal-large'}) ->
101
+ body = if options.html then msg else "<div class='alert alert-#{options.alert_class}'>#{msg}</div>"
102
+ clazz = if options.html then "modal-huge" else options.modal_class
103
103
  @show meta: panel: (panel_template: "close_m", template_string: body, title: title, class: clazz, footer: true) # message: msg,
104
104
 
105
+
106
+ info: (title, msg, options = {alert_class: 'info', modal_class: 'modal-large'}) -> @show_modal(title, msg, options)
107
+ warning: (title, msg, options = {alert_class: 'warning', modal_class: 'modal-large'}) -> @show_modal(title, msg, options)
108
+ error: (title, msg, options = {alert_class: 'danger', modal_class: 'modal-huge'}) -> @show_modal(title, msg, options)
109
+
105
110
  confirm: (title, msg, action) ->
106
111
  body = "<div class='alert alert-warning'>#{msg}</div>"
107
112
  clazz = "modal-large"
data/bower.json CHANGED
@@ -2,9 +2,10 @@
2
2
  "name": "engine2",
3
3
  "version": "1.0.0",
4
4
  "dependencies": {
5
- "angular-strap": "^2.3.10",
5
+ "angular-strap": "^2.3.12",
6
6
  "angular": "^1.5.8",
7
- "angular-websocket": "^2.0.0"
7
+ "angular-websocket": "^2.0.0",
8
+ "angular-toastr": "^2.1.1"
8
9
  },
9
10
  "overrides": {
10
11
  "angular": {
@@ -10,11 +10,14 @@
10
10
  :decode_selected: selected
11
11
  :list_select_selected: Selected
12
12
 
13
+ :E2Files: Files
14
+ :files: File
13
15
  :name: Name
14
16
  :mime: Mime
15
17
  :owner: Owner
16
18
  :model: Model
17
19
  :field: Field
20
+ :uploaded: Uploaded
18
21
  :updated: Updated
19
22
 
20
23
  :ok: Ok
@@ -10,11 +10,14 @@
10
10
  :decode_selected: wybranych
11
11
  :list_select_selected: Wybranych
12
12
 
13
+ :E2Files: Pliki
14
+ :files: Plik
13
15
  :name: Nazwa
14
16
  :mime: Mime
15
17
  :owner: Właściciel
16
18
  :model: Model
17
19
  :field: Pole
20
+ :uploaded: Wysłany
18
21
  :updated: Aktualizowany
19
22
 
20
23
  :ok: Ok
@@ -31,12 +34,12 @@
31
34
  :select_toggle: Zaznacz
32
35
  :confirm_delete: Usuń
33
36
  :confirm_delete_title: <span class='glyphicon glyphicon-trash'></span> Potwierdzenie
34
- :confirm_bulk_delete: Usuń zaznacznone
37
+ :confirm_bulk_delete: Usuń zaznaczone
35
38
  :delete_restricted: Blokujące relacje
36
39
  :confirm_bulk_delete_title: <span class='glyphicon glyphicon-trash'></span> Potwierdzenie
37
40
  :confirm_unlink: Odłącz
38
41
  :confirm_unlink_title: <span class='glyphicon glyphicon-minus'></span> Potwierdzenie
39
- :confirm_bulk_unlink: Odłącz zaznacznone
42
+ :confirm_bulk_unlink: Odłącz zaznaczone
40
43
  :confirm_bulk_unlink_title: <span class='glyphicon glyphicon-minus'></span> Potwierdzenie
41
44
  :debug_info: Debug info
42
45
  :show_meta: Metainfo
@@ -24,8 +24,8 @@ exports.config =
24
24
  files:
25
25
  javascripts:
26
26
  joinTo:
27
- 'engine2vendor.js': /^node_modules|bower_components/
28
- 'engine2.js': /^app/
27
+ 'assets/engine2vendor.js': /^node_modules|bower_components/
28
+ 'assets/engine2.js': /^app/
29
29
  order:
30
30
  before: [
31
31
  "app/engine2.coffee"
@@ -33,35 +33,36 @@ exports.config =
33
33
 
34
34
  stylesheets:
35
35
  joinTo:
36
- 'engine2vendor.css': /^node_modules/
37
- 'engine2.css': /^app/
38
- order:
39
- before: [
40
- /bootstrap.css$/
41
- ]
36
+ 'assets/engine2vendor.css': /^(?:node_modules||bower_components)\/(?!(bootstrap\/))/
37
+ 'assets/bootstrap.css': /^node_modules\/(bootstrap\/)/
38
+ 'assets/engine2.css': /^app/
39
+ # order:
40
+ # before: [
41
+ # /bootstrap\.css$/
42
+ # ]
42
43
 
43
44
  plugins:
44
45
  on: ["ng-annotate-brunch"]
45
46
 
46
47
  uglify:
47
- mangle: false
48
+ mangle: true
48
49
  compress:
49
50
  global_defs:
50
51
  DEBUG: false
51
52
 
52
53
  replacement:
53
54
  replacements: [
54
- files: [/vendor.js$/]
55
+ files: [/vendor\.js$/]
55
56
  match: (
56
57
  fix = "$modal.$element = compileData.link(modalScope, function(clonedElement, scope) {});"
57
58
  find: fix.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1")
58
59
  replace: "#{fix}$modal.$backdrop = backdropElement;"
59
- ),
60
- files: [/vendor\.css$/]
61
- match: (
62
- find: "../fonts"
63
- replace: "fonts"
64
60
  )
61
+ # files: [/\.css$/]
62
+ # match: (
63
+ # find: "../fonts"
64
+ # replace: "fonts"
65
+ # )
65
66
  ]
66
67
 
67
68
  copycat:
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency 'faye-websocket', '~> 0.10'
28
28
 
29
29
  spec.add_development_dependency "bundler", "~> 2.00"
30
- spec.add_development_dependency "rake", "~> 12"
30
+ spec.add_development_dependency "rake", "~> 13"
31
31
  end
@@ -69,7 +69,7 @@ module Engine2
69
69
  action = self.class.new(node, assets, self)
70
70
  result = action.instance_exec(handler, *action.request_action_proc_params(handler), &rmp)
71
71
  action.post_process
72
- response = @requestable ? (result || {}) : action.invoke(handler)
72
+ response = @requestable ? (result.is_a?(Hash) ? result : {}) : action.invoke(handler)
73
73
  response[:meta] = action.meta
74
74
  response
75
75
  else
@@ -82,7 +82,7 @@ module Engine2
82
82
  end
83
83
 
84
84
  def arguments args
85
- @meta[:arguments] = args
85
+ (@meta[:arguments] ||= {}).merge! args
86
86
  end
87
87
 
88
88
  def execute command
@@ -235,7 +235,8 @@ module Engine2
235
235
  class RootAction < Action
236
236
  def initialize *args
237
237
  super
238
- @meta.merge! environment: Handler::environment, application: Engine2::SETTINGS[:name], key_separator: Engine2::SETTINGS[:key_separator], ws_methods: ActionWebSocketSupport::WS_METHODS
238
+ @meta.merge! environment: Handler::environment, application: Engine2::SETTINGS[:name], uuid: SecureRandom.uuid,
239
+ key_separator: Engine2::SETTINGS[:key_separator], ws_methods: ActionWebSocketSupport::WS_METHODS
239
240
  end
240
241
  end
241
242
 
@@ -459,7 +460,7 @@ module Engine2
459
460
 
460
461
  module ActionAngularSupport
461
462
  def ng_execute expr
462
- (@meta[:execute] ||= "") << expr + ";"
463
+ (@meta[:execute] ||= String.new) << expr + ";"
463
464
  end
464
465
 
465
466
  def ng_record! name, value
@@ -586,13 +587,12 @@ module Engine2
586
587
  end
587
588
 
588
589
  module ActionOnChangeSupport
589
- def on_change field, &blk
590
+ def on_change field, trigger_on_start = false, &blk
590
591
  node_name = :"#{field}_on_change"
591
- nd = node.define_node node_name, (blk.arity > 2 ? OnChangeGetAction : OnChangePostAction)
592
+ nd = node.define_node node_name, (blk.arity <= 2 ? OnChangeGetAction : OnChangePostAction)
592
593
  nd.*{request &blk}
593
594
 
594
- fields! field, remote_onchange: node_name
595
- fields! field, remote_onchange_record: :true if blk.arity > 2
595
+ fields! field, remote_onchange: {action: node_name, record: blk.arity > 2, trigger_on_start: trigger_on_start}
596
596
  end
597
597
 
598
598
  class OnChangeAction < Action
@@ -608,9 +608,9 @@ module Engine2
608
608
  end
609
609
  end
610
610
 
611
- def invoke handler
612
- {}
613
- end
611
+ # def invoke handler
612
+ # {}
613
+ # end
614
614
  end
615
615
 
616
616
  class OnChangeGetAction < OnChangeAction
@@ -635,17 +635,17 @@ module Engine2
635
635
 
636
636
  module ActionListSupport
637
637
  include ActionModelSupport, ActionAPISupport, ActionTabSupport, ActionPanelSupport, ActionMenuSupport, ActionOnChangeSupport, ActionDraggableSupport
638
- attr_reader :filters, :orders
638
+ attr_reader :filters, :orders, :default_order_field
639
639
 
640
640
  def pre_run
641
641
  super
642
642
  config.merge!(per_page: 10, use_count: false, selectable: true) # search_active: false,
643
643
 
644
644
  panel_template 'scaffold/list'
645
- panel_title "#{:list.icon} #{LOCS[assets[:model].name.to_sym]}"
645
+ panel_title "#{assets[:model].model_icon.icon} #{LOCS[assets[:model].model_route]}"
646
646
  loc! LOCS[:list_locs]
647
647
  menu :menu do
648
- properties break: 2, group_class: "btn-group-xs"
648
+ properties break: 2, group_class: "btn-group-sm"
649
649
  option :search_toggle, icon: "search", show: "action.meta.search_field_list", active: "action.ui_state.search_active", button_loc: false
650
650
  # divider
651
651
  option :refresh, icon: "refresh", button_loc: false
@@ -657,7 +657,7 @@ module Engine2
657
657
  end
658
658
 
659
659
  menu :item_menu do
660
- properties break: 1, group_class: "btn-group-xs"
660
+ properties break: 1, group_class: "btn-group-sm"
661
661
  end
662
662
 
663
663
  @meta[:state] = [:query, :ui_state]
@@ -676,6 +676,8 @@ module Engine2
676
676
  end
677
677
 
678
678
  def post_run
679
+ super
680
+
679
681
  unless panel[:class]
680
682
  panel_class case @meta[:field_list].size
681
683
  when 1..3; ''
@@ -684,7 +686,6 @@ module Engine2
684
686
  end
685
687
  end
686
688
 
687
- super
688
689
  @meta[:primary_fields] = assets[:model].primary_keys
689
690
  end
690
691
 
@@ -744,8 +745,15 @@ module Engine2
744
745
  fields! *flds, sort: true
745
746
  end
746
747
 
748
+ def default_order order
749
+ @default_order_field = order
750
+ end
751
+
747
752
  def search_live *flds
748
- flds = @meta[:search_field_list] if flds.empty?
753
+ if flds.empty?
754
+ flds = @meta[:search_field_list]
755
+ @meta[:disable_search_button] = true
756
+ end
749
757
  fields! *flds, search_live: true
750
758
  end
751
759
 
@@ -770,8 +778,12 @@ module Engine2
770
778
  end
771
779
 
772
780
  def filter_case_insensitive name
773
- raise E2Error.new("Field '#{name}' needs to be a string one") unless assets[:model].find_type_info(name)[:otype] == :string
774
- filter(name){|handler, query, hash| query.where(name.ilike("%#{hash[name]}%")) }
781
+ model = assets[:model]
782
+ raise E2Error.new("Field '#{name}' needs to be a string") unless model.find_type_info(name)[:otype] == :string
783
+ filter name do |handler, query, hash|
784
+ value = hash[name]
785
+ value ? query.where(model.table_name.q(name).ilike("%#{value}%")) : query
786
+ end
775
787
  end
776
788
 
777
789
  def order name, &blk
@@ -817,7 +829,10 @@ module Engine2
817
829
  model = assets[:model]
818
830
  handler.permit json_rec.is_a?(Hash)
819
831
  val_fields = (dynamic? ? static.validate_fields : @validate_fields) || model.type_info.keys
820
- handler.permit (json_rec.keys - val_fields).empty?
832
+ left_fields = (json_rec.keys - val_fields)
833
+
834
+ puts "Left: #{left_fields.inspect}" unless left_fields.empty?
835
+ handler.permit left_fields.empty?
821
836
 
822
837
  record = model.call(json_rec)
823
838
  record.validate_fields = val_fields
@@ -1025,6 +1040,14 @@ module Engine2
1025
1040
  def hr_after field, message = '-'
1026
1041
  fields! field, hr: message
1027
1042
  end
1043
+
1044
+ def create?
1045
+ @action_type == :create
1046
+ end
1047
+
1048
+ def modify?
1049
+ @action_type == :modify
1050
+ end
1028
1051
  end
1029
1052
 
1030
1053
  module ActionCreateSupport
@@ -1037,7 +1060,7 @@ module Engine2
1037
1060
  def pre_run
1038
1061
  super
1039
1062
  panel_title "#{LOCS[:create_title]} - #{LOCS[assets[:model].table_name]}"
1040
- node.parent.*.menu(:menu).option_at 0, node.name, icon: "plus-sign", button_loc: false if node.parent.*.is_a?(ListAction)
1063
+ node.parent.*.menu(:menu).option_at 0, node.name, icon: "plus-sign", button_loc: false if node.parent.*.is_a?(ActionListSupport)
1041
1064
 
1042
1065
  hide_pk unless assets[:model].natural_key
1043
1066
  end
@@ -1305,6 +1328,10 @@ module Engine2
1305
1328
  action.fields(field)[:render] ||= {}
1306
1329
  action.fields(field)[:render].merge! format: info[:format], model_format: info[:model_format] # Model::DEFAULT_DATE_FORMAT
1307
1330
  },
1331
+ datetime: lambda{|action, field, info|
1332
+ action.fields(field)[:render] ||= {}
1333
+ action.fields(field)[:render].merge! format: info[:date_format], model_format: info[:date_model_format] # Model::DEFAULT_DATE_FORMAT
1334
+ },
1308
1335
  decimal_date: lambda{|action, field, info|
1309
1336
  SearchRendererPostProcessors[:date].(action, field, info)
1310
1337
  }
@@ -1330,11 +1357,11 @@ module Engine2
1330
1357
  email: lambda{|action, info| Templates.email(info[:length])},
1331
1358
  password: lambda{|action, info| Templates.password(info[:length])},
1332
1359
  # date_range: lambda{|action, info| Templates.date_range},
1333
- boolean: lambda{|action, info| Templates.checkbox_buttons(optional: !info[:required])},
1360
+ boolean: lambda{|action, info| Templates.checkbox_button},
1334
1361
  currency: lambda{|action, info| Templates.currency},
1335
1362
  list_select: lambda{|action, info|
1336
1363
  length = info[:values].length
1337
- max_length = info[:values].map(&:last).max_by(&:length).length
1364
+ max_length = length > 0 ? info[:values].map(&:last).max_by(&:length).length : 0
1338
1365
  if info[:multiselect]
1339
1366
  Templates.list_bsmselect(max_length)
1340
1367
  elsif length <= 3
@@ -1360,6 +1387,7 @@ module Engine2
1360
1387
 
1361
1388
  (DefaultSearchRenderers ||= {}).merge!(
1362
1389
  date: lambda{|action, info| SearchTemplates.date_range},
1390
+ datetime: lambda{|action, info| SearchTemplates.date_range},
1363
1391
  decimal_date: lambda{|action, info| SearchTemplates.date_range},
1364
1392
  integer: lambda{|action, info| SearchTemplates.integer_range},
1365
1393
  string: lambda{|action, info| SearchTemplates.input_text},
@@ -93,4 +93,97 @@ module Engine2
93
93
  entries
94
94
  end
95
95
  end
96
- end
96
+
97
+ class ArrayViewAction < Action
98
+ include ActionViewSupport
99
+
100
+ def find_record handler, id
101
+ node.parent.*.data_source(handler)[id.to_i]
102
+ end
103
+ end
104
+
105
+ class ArrayFormAction < Action
106
+ end
107
+
108
+ class ArrayCreateAction < ArrayFormAction
109
+ include ActionCreateSupport
110
+ end
111
+
112
+ class ArrayModifyAction < ArrayFormAction
113
+ include ActionModifySupport
114
+
115
+ def find_record handler, id
116
+ node.parent.*.data_source(handler)[id.to_i]
117
+ end
118
+ end
119
+
120
+ class ArrayDeleteAction < Action
121
+ include ActionDeleteSupport
122
+
123
+ def invoke handler
124
+ handler.permit id = handler.params[:id]
125
+ node.parent.parent.*.data_source(handler).delete_at(id.to_i)
126
+ end
127
+ end
128
+
129
+ class ArraySaveAction < Action
130
+ include ActionApproveSupport
131
+ end
132
+
133
+ class ArrayInsertAction < ArraySaveAction
134
+ include ActionInsertSupport
135
+ action_type :approve
136
+
137
+ def after_approve handler, record
138
+ # handler.permit id = record[:id]
139
+ # ds = node.parent.parent.*.data_source(handler)
140
+ end
141
+ end
142
+
143
+ class ArrayUpdateAction < ArraySaveAction
144
+ include ActionUpdateSupport
145
+ action_type :approve
146
+
147
+ def after_approve handler, record
148
+ handler.permit id = record[:id]
149
+ node.parent.parent.*.data_source(handler)[id].merge!(record.values)
150
+ end
151
+ end
152
+
153
+ class Schemes
154
+ ARRAY_CRUD ||= {array_create: true, array_view: true, array_modify: true, array_delete: true}.freeze
155
+ ARRAY_VIEW ||= {array_view: true}
156
+ end
157
+
158
+ SCHEMES.instance_eval do
159
+ define_scheme :array_view do |name = :view|
160
+ define_node name, ArrayViewAction
161
+ end
162
+
163
+ define_scheme :array_modify do |name = :modify|
164
+ define_node name, ArrayModifyAction do
165
+ define_node :approve, ArrayUpdateAction
166
+ end
167
+ end
168
+
169
+ define_scheme :array_create do |name = :create|
170
+ define_node name, ArrayCreateAction do
171
+ define_node :approve, ArrayInsertAction
172
+ end
173
+ end
174
+
175
+ define_scheme :array_delete do
176
+ run_scheme :confirm, :delete, ArrayDeleteAction,
177
+ message: LOCS[:delete_question], title: LOCS[:confirm_delete_title]
178
+ end
179
+
180
+ define_scheme :array do |name, model, options|
181
+ options ||= Schemes::ARRAY_CRUD
182
+ define_node name, ArrayListAction, model: model do
183
+ options.each{|k, v| run_scheme(k) if v}
184
+
185
+ define_node_bundle :form, :create, :modify if options[:array_create] && options[:array_modify]
186
+ end
187
+ end
188
+ end
189
+ end