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
@@ -26,6 +26,8 @@ module Engine2
26
26
  @before_destroy_processors = nil
27
27
  @after_destroy_processors = nil
28
28
  @type_info_synchronized = nil
29
+ @model_icon = :"list"
30
+ @model_route = cls.name.to_sym
29
31
  end
30
32
  cls.setup_schema
31
33
  end
@@ -54,12 +56,12 @@ module Engine2
54
56
  when :integer
55
57
  integer_field name
56
58
  when :string
57
- if db_info[:db_type] == 'text'
58
- string_field name, 10
59
+ string_field name, case db_info[:db_type]
60
+ when 'text', 'character varying'
61
+ 100
59
62
  else
60
- string_field name, Integer(db_info[:column_size] || db_info[:db_type][/\((\d+)\)/, 1])
63
+ Integer(db_info[:column_size] || db_info[:db_type][/\((\d+)\)/, 1])
61
64
  end
62
-
63
65
  when :time
64
66
  time_field name, LOCS[:default_time_format], LOCS[:default_time_model_format]
65
67
  when :date
@@ -176,10 +178,17 @@ module Engine2
176
178
 
177
179
  def scheme s_name = :default, opts = nil, &blk
178
180
  @scheme_name = s_name
179
- @scheme_args = [name.to_sym, self, opts]
180
- SCHEMES::define_scheme name.to_sym, &blk
181
+ @scheme_args = [model_route, self, opts]
182
+ SCHEMES::define_scheme model_route, &blk
183
+ end
184
+
185
+ def model_icon icn = nil
186
+ icn ? @model_icon = icn : @model_icon
181
187
  end
182
188
 
189
+ def model_route rt = nil
190
+ rt ? @model_route = rt : @model_route
191
+ end
183
192
  end
184
193
 
185
194
  # def define_dummy_model
@@ -374,7 +383,7 @@ module Engine2
374
383
  value.join(info[:separator])
375
384
  when :integer
376
385
  value.reduce(0, :|)
377
- end if value && info[:multiselect]
386
+ end if value && info[:multiselect] && !info[:dummy]
378
387
  }
379
388
  )
380
389
 
@@ -382,7 +391,7 @@ module Engine2
382
391
  file_store: lambda{|m, v, info|
383
392
  value = m.values[v]
384
393
  files = E2Files.db[:files]
385
- owner = m.primary_key_values.join('|')
394
+ owner = Sequel::join_keys(m.primary_key_values)
386
395
  upload = info[:store][:upload]
387
396
  files_dir = info[:store][:files]
388
397
  value.each do |entry|
@@ -426,7 +435,7 @@ module Engine2
426
435
  file_store: lambda{|m, v, info|
427
436
  files = E2Files.db[:files]
428
437
  files_dir = info[:store][:files]
429
- owner = m.primary_key_values.join('|')
438
+ owner = Sequel::join_keys(m.primary_key_values)
430
439
  files.select(:id, :name).where(owner: owner, model: m.model.name, field: v.to_s).all.each do |entry|
431
440
  File.delete("#{files_dir}/#{entry[:name]}_#{entry[:id]}")
432
441
  end
@@ -14,6 +14,8 @@ module Engine2
14
14
 
15
15
  class E2Files < Sequel::Model(E2DB[:files])
16
16
  extend Engine2::Model
17
+ model_icon :'file'
18
+ model_route :E2Files
17
19
 
18
20
  type_info do
19
21
  # list_select :model, Hash[@model.db.models.keys.map{|m| [m, m]}]
@@ -133,7 +133,7 @@ module Engine2
133
133
  end
134
134
 
135
135
  define_scheme :star_to_many do |assoc_name, assoc, model|
136
- action.menu(:item_menu).option assoc_name, icon: "list" # , click: "action.show_assoc($index, \"#{assoc_name}!\")"
136
+ action.menu(:item_menu).option assoc_name, icon: Kernel::const_get(assoc[:class_name]).model_icon # , click: "action.show_assoc($index, \"#{assoc_name}!\")"
137
137
  options = assoc[:options] || Schemes::LINK
138
138
  define_node assoc_name, StarToManyListAction, model: model, assoc: assoc do
139
139
  options.each{|k, v| run_scheme(k) if v}
@@ -236,10 +236,5 @@ module Engine2
236
236
  end
237
237
  end
238
238
  end
239
-
240
- define_scheme :array do |name, model|
241
- define_node name, ArrayListAction, model: model do
242
- end
243
- end
244
239
  end
245
240
  end
@@ -63,8 +63,13 @@ module Engine2
63
63
  end
64
64
 
65
65
  def list_select length, options = {}
66
+ template = if options[:multiple]
67
+ "fields/list_mselect"
68
+ else
69
+ options[:optional] ? "fields/list_select_opt" : "fields/list_select"
70
+ end
66
71
  options.merge({
67
- template: options[:optional] ? "fields/list_select_opt" : "fields/list_select",
72
+ template: template,
68
73
  length: length
69
74
  })
70
75
  end
@@ -91,6 +96,12 @@ module Engine2
91
96
  })
92
97
  end
93
98
 
99
+ def list_mbuttons options = {}
100
+ options.merge({
101
+ template: options[:optional] ? "fields/list_mbuttons_opt" : "fields/list_mbuttons"
102
+ })
103
+ end
104
+
94
105
  def select_picker options = {}
95
106
  options.merge({
96
107
  template: options[:optional] ? "fields/select_picker_opt" : "fields/select_picker"
@@ -117,8 +128,8 @@ module Engine2
117
128
  })
118
129
  end
119
130
 
120
- def typeahead_picker
121
- {template: "fields/typeahead_picker", animation: BS_ANIMATION}
131
+ def typeahead_picker options = {}
132
+ {template: "fields/typeahead_picker", length: 20, limit: 10, min_length: 0, animation: BS_ANIMATION}.merge(options)
122
133
  end
123
134
 
124
135
  def email length
@@ -147,6 +158,10 @@ module Engine2
147
158
  })
148
159
  end
149
160
 
161
+ def checkbox_button options = {}
162
+ {template: "fields/checkbox_button"}.merge(options)
163
+ end
164
+
150
165
  def radio_checkbox
151
166
  {template: "fields/radio_checkbox"}
152
167
  end
@@ -171,6 +186,13 @@ module Engine2
171
186
  })
172
187
  end
173
188
 
189
+ def date_picker options = {}
190
+ options.merge({
191
+ template: "search_fields/date",
192
+ animation: BS_ANIMATION
193
+ })
194
+ end
195
+
174
196
  def integer_range
175
197
  {template: "search_fields/integer_range"}
176
198
  end
@@ -199,8 +221,8 @@ module Engine2
199
221
  })
200
222
  end
201
223
 
202
- def typeahead_picker
203
- {template: "search_fields/typeahead_picker", animation: BS_ANIMATION}
224
+ def typeahead_picker options = {}
225
+ {template: "search_fields/typeahead_picker", limit: 10, min_length: 0, animation: BS_ANIMATION}.merge(options)
204
226
  end
205
227
 
206
228
  # def checkbox_search true_v = "1", false_v = "0"
@@ -230,9 +252,13 @@ module Engine2
230
252
  {template: "search_fields/list_buttons"}
231
253
  end
232
254
 
255
+ def list_mbuttons
256
+ {template: "search_fields/list_mbuttons"}
257
+ end
258
+
233
259
  def decimal_date
234
260
  {template: "search_fields/decimal_date_range", animation: BS_ANIMATION}
235
261
  end
236
262
  end
237
263
  end
238
- end
264
+ end
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Engine2
5
-
6
5
  class TypeInfo
7
6
  def initialize model
8
7
  @model = model
@@ -74,7 +73,7 @@ module Engine2
74
73
  end
75
74
  end
76
75
 
77
- def boolean field, true_value = 1, false_value = 0
76
+ def boolean field, true_value = true, false_value = false
78
77
  modify_field field do |info|
79
78
  info[:type] = :boolean
80
79
  info[:true_value] = true_value
@@ -244,6 +243,12 @@ module Engine2
244
243
  end
245
244
  end
246
245
 
246
+ def length field, len
247
+ modify_field field do |info|
248
+ info[:length] = len
249
+ end
250
+ end
251
+
247
252
  def date_range from, to
248
253
  depends_on(from, to)
249
254
  modify_field from do |info|
@@ -338,7 +343,7 @@ module Engine2
338
343
 
339
344
  raise E2Error.new("type '#{values.class}' not supported for list_select modifier for field #{name}") unless values.is_a?(Hash)
340
345
  info[:values] = values.to_a
341
- info[:validations][:list_select] = true
346
+ info[:validations][:list_select] = true unless values.empty?
342
347
  end
343
348
  end
344
349
 
@@ -364,6 +369,5 @@ module Engine2
364
369
  info[:sequence] = seq_name
365
370
  end
366
371
  end
367
-
368
372
  end
369
- end
373
+ end
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Engine2
5
- MAJOR, MINOR, TINY = [1, 0, 8]
5
+ MAJOR, MINOR, TINY = [1, 0, 9]
6
6
  VERSION = [MAJOR, MINOR, TINY].join('.').freeze
7
7
  def self.version
8
8
  VERSION
@@ -9,23 +9,24 @@
9
9
  "build": "brunch build --production"
10
10
  },
11
11
  "dependencies": {
12
- "@uirouter/angularjs": "^1.0.22",
13
- "@uirouter/core": "^5.0.23",
14
- "angular": "^1.7.8",
15
- "angular-animate": "^1.7.8",
16
- "angular-cookies": "^1.7.8",
12
+ "@uirouter/angularjs": "1.0.23",
13
+ "@uirouter/core": "6.0.1",
14
+ "angular": "^1.8.0",
15
+ "angular-animate": "^1.8.0",
16
+ "angular-cookies": "^1.8.0",
17
17
  "angular-drag-and-drop-lists": "^2.1.0",
18
18
  "angular-load": "^0.5.0",
19
19
  "angular-local-storage": "^0.7.0",
20
20
  "angular-motion": "^0.4.0",
21
- "angular-sanitize": "^1.7.8",
21
+ "angular-sanitize": "^1.8.0",
22
22
  "angular-ui-tree": "^2.22.0",
23
23
  "bootstrap": "^3.4.1",
24
24
  "bootstrap-additions": "0.3.1",
25
25
  "fork-awesome": "^1.1.7",
26
- "lodash": "^4.17.11",
26
+ "json-to-pretty-yaml": "1.2.2",
27
+ "lodash": "^4.17.15",
27
28
  "ng-file-upload": "^12.2.0",
28
- "push.js": "^1.0.9"
29
+ "push.js": "^1.0.12"
29
30
  },
30
31
  "devDependencies": {
31
32
  "auto-reload-brunch": "^2.7.1",
@@ -0,0 +1,6 @@
1
+ .col-lg-12
2
+ .div ng-init="(action.record[f] === null || action.record[f] === undefined) && (action.record[f] = field.render.false_value)" ng-model="action.record[f]" e2-field=""
3
+ a.btn.btn-default.btn-sm ng-show="action.record[f] === field.render.true_value" ng-class="action.record[f] === field.render.true_value && 'active'" ng-click="action.record[f] = field.render.false_value" ng-disabled="field.disabled"
4
+ span.glyphicon.glyphicon-check
5
+ a.btn.btn-default.btn-sm ng-show="action.record[f] === field.render.false_value" ng-click="action.record[f] = field.render.true_value" ng-disabled="field.disabled"
6
+ span.glyphicon.glyphicon-unchecked
@@ -1,5 +1,5 @@
1
1
  .col-lg-12
2
- .btn-group.btn-group-sm ng-init="(action.record[f] === undefined) && (action.record[f] = field.render.false_value)" ng-model="action.record[f]" e2-field=""
2
+ .btn-group.btn-group-sm ng-init="(action.record[f] === null || action.record[f] === undefined) && (action.record[f] = field.render.false_value)" ng-model="action.record[f]" e2-field=""
3
3
  a.btn.btn-default ng-class="action.record[f] === field.render.true_value && 'active'" ng-click="action.record[f] = field.render.true_value" ng-disabled="field.disabled"
4
4
  span.glyphicon.glyphicon-check
5
5
  a.btn.btn-default ng-class="action.record[f] === field.render.false_value && 'active'" ng-click="action.record[f] = field.render.false_value" ng-disabled="field.disabled"
@@ -0,0 +1,9 @@
1
+ .col-lg-12
2
+ .btn-group.btn-group-sm ng-model="action.record[f]" e2-field=""
3
+ a.btn.btn-default[
4
+ ng-class="action.record[f].includes(v[0]) && 'active'"
5
+ ng-click="action.record[f].includes(v[0]) ? action._().pull(action.record[f], v[0]) : action.record[f].push(v[0])"
6
+ ng-repeat="v in field.render.values"
7
+ ng-bind-html="v[1]"
8
+ ng-disabled="field.disabled"
9
+ ]
@@ -0,0 +1,11 @@
1
+ .col-lg-12
2
+ .btn-group.btn-group-sm ng-model="action.record[f]" e2-field=""
3
+ a.btn.btn-default[
4
+ ng-class="action.record[f].includes(v[0]) && 'active'"
5
+ ng-click="action.record[f].includes(v[0]) ? action._().pull(action.record[f], v[0]) : action.record[f].push(v[0])"
6
+ ng-repeat="v in field.render.values"
7
+ ng-bind-html="v[1]"
8
+ ng-disabled="field.disabled"
9
+ ]
10
+ a.btn.btn-default ng-disabled="action.record[f].length == 0 || field.disabled" ng-click="action.record[f] = []"
11
+ span.glyphicon.glyphicon-remove
@@ -0,0 +1,12 @@
1
+ /.col-lg-7.col-md-8.col-sm-12
2
+ div e2-input-cols="{{::field.render.length}}"
3
+ select.btn.btn-default.btn-sm [
4
+ multiple="true"
5
+ size="{{field.render.size}}"
6
+ ng-model="action.record[f]"
7
+ ng-options="v[0] as v[1] for v in field.render.values"
8
+ ng-disabled="field.disabled"
9
+ ng-class="field.render.class"
10
+ class="form-control input-sm"
11
+ e2-field=""
12
+ ]
@@ -1,2 +1,2 @@
1
- .col-lg-10.col-md-10.col-sm-10
1
+ .col-lg-12.col-md-12.col-sm-10
2
2
  e2-action action="field.assoc"
@@ -1,11 +1,12 @@
1
1
  e2-action action="[field.assoc, 'typeahead']"
2
- .col-lg-7.col-md-8.col-sm-12
2
+ /.col-lg-7.col-md-8.col-sm-12
3
+ div e2-input-cols="{{::field.render.length}}"
3
4
  .input-group.input-group-sm
4
5
  input.btn.btn-default [
6
+ style="text-align:left"
5
7
  type="text"
6
8
  ng-model="action.decode"
7
- bs-options="v.value for v in action.load($viewValue)"
8
- ng-keypress="action.key_pressed = true"
9
+ bs-options="v.value for v in action.load(action.decode)"
9
10
 
10
11
  ng-disabled="field.disabled"
11
12
  ng-class="field.render.class"
@@ -14,11 +15,13 @@ e2-action action="[field.assoc, 'typeahead']"
14
15
  data-animation="{{::field.render.animation}}"
15
16
  placeholder="..."
16
17
  data-html="true"
17
- data-limit="10"
18
+ data-limit="{{::field.render.limit}}"
19
+ data-min-length="{{::field.render.min_length}}"
20
+ data-trigger="focus"
18
21
  bs-typeahead=""
19
22
  e2-field=""
20
23
  ]
21
24
  span.input-group-addon: span.glyphicon.glyphicon-font
22
25
  .input-group-btn
23
- a.btn.btn-default ng-disabled="field.disabled || action.decode == null" ng-click="!field.disabled && action.reset()"
26
+ a.btn.btn-default ng-disabled="field.disabled || !action.decode" ng-click="!field.disabled && action.reset()"
24
27
  span.glyphicon.glyphicon-off
@@ -1,4 +1,4 @@
1
- e2-action action="'inspect'"
1
+ e2-action action="'inspect_' + action.globals().application"
2
2
  div bs-tabs=""
3
3
  br
4
4
  div title="API" bs-pane=""
@@ -8,7 +8,7 @@ e2-action action="'inspect'"
8
8
  .panel-body
9
9
  script type="text/ng-template" id="nodes_renderer.html"
10
10
  div data-nodrag="" ng-init="stack = stack.concat([$index])"
11
- span.glyphicon.glyphicon-cog ng-if="node.terminal"
11
+ span.glyphicon ng-class="{'glyphicon-cog': node.access, 'glyphicon-exclamation-sign': !node.access}" ng-if="node.terminal"
12
12
  a ng-click="action.open(stack, node, collapsed, true); toggle(this)" ng-if="!node.terminal"
13
13
  span.glyphicon ng-class="{'glyphicon-play-circle': collapsed && node.access, 'glyphicon-download': !collapsed, 'glyphicon-exclamation-sign': collapsed && !node.access}"
14
14
  span< ng-bind="node.name + ' ' + node.number" ng-click="action.open(stack, node, collapsed, false)" style="cursor: pointer; {{action.number == node.number && 'font-weight: bold;'}}"
@@ -24,13 +24,13 @@ e2-action action="'inspect'"
24
24
  div bs-tabs="" bs-active-pane="actionTab" ng-init="actionTab = 0"
25
25
  div title="Action" bs-pane=""
26
26
  br
27
- pre ng-bind="action.action_json | json"
27
+ pre ng-bind="action.action_json | yaml"
28
28
  div title="Meta" bs-pane=""
29
29
  br
30
- pre ng-bind="action.meta_json | json"
30
+ pre ng-bind="action.meta_json | yaml"
31
31
  div title="State" bs-pane=""
32
32
  br
33
- pre ng-bind="action.action_state | json"
33
+ pre ng-bind="action.action_state | yaml"
34
34
 
35
35
  div title="Model" bs-pane=""
36
36
  .row
@@ -58,13 +58,13 @@ e2-action action="'inspect'"
58
58
  div bs-tabs="" bs-active-pane="modelTab" ng-init="modelTab = 0"
59
59
  div title="Model" bs-pane=""
60
60
  br
61
- pre ng-bind="action.model.info | json"
61
+ pre ng-bind="action.model.info | yaml"
62
62
  div title="Schema" bs-pane=""
63
63
  br
64
- pre ng-bind="action.model.schema | json"
64
+ pre ng-bind="action.model.schema | yaml"
65
65
  div title="Type info" bs-pane=""
66
66
  br
67
- pre ng-bind="action.model.type_info | json"
67
+ pre ng-bind="action.model.type_info | yaml"
68
68
  div title="Associations" bs-pane="" ng-if="action.model && action.has_assoc(action.model)"
69
69
  br
70
70
  .row
@@ -78,36 +78,39 @@ e2-action action="'inspect'"
78
78
  br
79
79
  .row
80
80
  .col-lg-12
81
- pre ng-bind="action.activeAssoc | json"
81
+ pre ng-bind="action.activeAssoc | yaml"
82
82
  div title="Globals" bs-pane=""
83
83
  .panel.panel-default
84
84
  .panel-body
85
- pre ng-bind="action.globals() | json"
85
+ pre ng-bind="action.globals() | yaml"
86
86
 
87
87
  div title="Environment" bs-pane=""
88
88
  .panel.panel-default
89
89
  .panel-body
90
- pre ng-bind="action.environment | json"
90
+ pre ng-bind="action.environment | yaml"
91
91
 
92
92
  div title="Local storage" bs-pane=""
93
93
  .panel.panel-default
94
94
  .panel-body
95
- pre ng-bind="action.local_storage | json"
96
- pre ng-bind="action.local_storage.keys() | json"
95
+ pre ng-bind="action.local_storage | yaml"
96
+ pre ng-bind="action.local_storage.keys() | yaml"
97
97
  a.btn.btn-default ng-click="action.local_storage.clearAll()"
98
98
  | Clear
99
99
 
100
100
  div title="Diagnostics" bs-pane=""
101
101
  .panel.panel-default
102
102
  .panel-body
103
- a.btn.btn-default ng-click="action.globals().notification('Name', 'Body', undefined, 2000)"
104
- | Push
103
+ .btn-group
104
+ a.btn.btn-default ng-click="action.globals().notification('Name', 'Body', undefined, 2000)"
105
+ | Push
106
+ a.btn.btn-default ng-click="action.globals().toastr().success('Name', 'Body')"
107
+ | Toastr
105
108
  hr
106
109
  a.btn.btn-default> ng-click="action.web_socket().send({number: action.number})"
107
110
  | Websocket
108
111
  | {{action.number}}
109
112
  br
110
113
  | Event
111
- pre ng-bind="action.event | json"
114
+ pre ng-bind="action.event | yaml"
112
115
  | Socket
113
116
  pre ng-bind="action.web_socket() | json"