glib-web 4.8.1 → 4.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/glib/json/traversal.rb +45 -2
  3. data/app/helpers/glib/json_ui/abstract_builder.rb +2 -0
  4. data/app/helpers/glib/json_ui/action_builder/browsers.rb +1 -1
  5. data/app/helpers/glib/json_ui/action_builder/storage_items.rb +2 -0
  6. data/app/helpers/glib/json_ui/action_builder/windows.rb +2 -1
  7. data/app/helpers/glib/json_ui/action_builder.rb +8 -4
  8. data/app/helpers/glib/json_ui/builder/mouse_events.rb +22 -22
  9. data/app/helpers/glib/json_ui/menu_builder.rb +1 -0
  10. data/app/helpers/glib/json_ui/view_builder/panels.rb +99 -0
  11. data/app/helpers/glib/json_ui/view_builder.rb +2 -0
  12. data/app/views/json_ui/garage/actions/_cookies.json.jbuilder +10 -0
  13. data/app/views/json_ui/garage/actions/_detects.json.jbuilder +16 -0
  14. data/app/views/json_ui/garage/actions/_list.json.jbuilder +4 -0
  15. data/app/views/json_ui/garage/actions/_storage_item.jbuilder +27 -0
  16. data/app/views/json_ui/garage/actions/_windows.json.jbuilder +4 -0
  17. data/app/views/json_ui/garage/forms/bulk_edit_post.json.jbuilder +17 -0
  18. data/app/views/json_ui/garage/forms/bulk_edit_post2.json.jbuilder +16 -0
  19. data/app/views/json_ui/garage/forms/dynamic_group.json.jbuilder +37 -14
  20. data/app/views/json_ui/garage/lists/edit_actions.json.jbuilder +1 -1
  21. data/app/views/json_ui/garage/panels/vertical.json.jbuilder +1 -1
  22. data/app/views/json_ui/garage/tables/bulk_edit.json.jbuilder +101 -0
  23. data/app/views/json_ui/garage/tables/index.json.jbuilder +6 -3
  24. data/app/views/json_ui/garage/views/components_replace.json.jbuilder +9 -1
  25. data/app/views/json_ui/garage/views/controls.json.jbuilder +1 -1
  26. data/lib/glib/json_crawler/action_crawlers/forms_submit.rb +26 -10
  27. data/lib/glib/json_crawler/router.rb +39 -8
  28. metadata +6 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4af5ec6464503d4acd2375f22f2e7dbde209b628be35a6b749761a360e8ff061
4
- data.tar.gz: d5447a14755f928524a26367f1ef9a132c773d8d2bce6bb3380be3503b7532eb
3
+ metadata.gz: bd7cc62da4019492821f41a143535746725e97014c265ee5d887271bc8350f92
4
+ data.tar.gz: 6cb94c5b31c3ee5a21f3bb7de0dadf622144a4986a68e82820103d9194145973
5
5
  SHA512:
6
- metadata.gz: 12b6d7f44ef0255a67551dc26ef975ffa474d6fbfbeca8603769e26fd05af893b186efe4a8837e4a98f5f36e9da3aa4b8d191d8a8f8413304cbaafe31e4e1d2f
7
- data.tar.gz: 5ff79df928df12a4d3fdbdf7c8d5badd688bdd37c887573d4abfdeae4adbdf19e24bfc8abc79d8d2d29fa4f4ed74725c3878232ce42e06fd06908ccb328b02a9
6
+ metadata.gz: 404991efb9cc61da56f2c886beeeb5a4779e0731dc03dcd30d70d143568e2cc0934dd2a9999b566f71a3fe30f76e17e323b210735606c5627c28f4db8a7105b3
7
+ data.tar.gz: b50e1fc04dab26be8c9bed1ac410cac570b556146fde3397987aaab6c09bd1283169cec978ebb317c2cd2517c223c7d3d81227e6e99e3508e80c15b471b1e695
@@ -33,10 +33,13 @@ module Glib::Json::Traversal
33
33
 
34
34
  class Visitor
35
35
  # Used in test crawler
36
- attr_reader :forms
36
+ attr_reader :forms, :component_registries, :deferred_actions
37
37
 
38
- def initialize
38
+ def initialize(crawler_test: false)
39
+ @crawler_test = crawler_test
40
+ @component_registries = []
39
41
  @forms = []
42
+ @deferred_actions = []
40
43
  end
41
44
 
42
45
  def fullPageForm(spec)
@@ -44,15 +47,36 @@ module Glib::Json::Traversal
44
47
  end
45
48
 
46
49
  def begin_page(spec)
50
+ return unless @crawler_test
51
+
47
52
  if (form = fullPageForm(spec))
48
53
  @forms << form
49
54
  end
55
+
56
+ @component_registries << {}
57
+ @deferred_actions << []
50
58
  end
51
59
 
52
60
  def end_page(spec)
61
+ return unless @crawler_test
62
+
53
63
  if fullPageForm(spec)
54
64
  @forms.pop
55
65
  end
66
+
67
+ current_actions = @deferred_actions.pop
68
+
69
+ # Execute actions with target IDs to ensure the target components have been loade.
70
+ current_actions.each do |action|
71
+ action, target_id = action.values
72
+ if (view_spec = current_component_registry[target_id])
73
+ action.execute(view_spec) if action
74
+ else
75
+ raise "View not found for ID: #{target_id}"
76
+ end
77
+ end
78
+
79
+ @component_registries.pop
56
80
  end
57
81
 
58
82
  def traverse_multiple(views, block)
@@ -74,7 +98,26 @@ module Glib::Json::Traversal
74
98
  traverse_multiple view['childViews'], block if view
75
99
  end
76
100
 
101
+ def current_deferred_actions
102
+ @deferred_actions.last
103
+ end
104
+
105
+ def current_component_registry
106
+ @component_registries.last
107
+ end
108
+
109
+ def defer_action(action_crawler, target_id)
110
+ current_deferred_actions << {
111
+ action: action_crawler,
112
+ target_id: target_id
113
+ }
114
+ end
115
+
77
116
  def traverse_single(view, block)
117
+ if @crawler_test && (view_id = view['id'])
118
+ current_component_registry[view_id] = view
119
+ end
120
+
78
121
  block.call view
79
122
 
80
123
  # Generic view children
@@ -281,6 +281,8 @@ module Glib
281
281
 
282
282
  def self.hash(propName, **options)
283
283
  define_method(propName) do |value|
284
+ return if value.nil?
285
+
284
286
  value = ActiveSupport::HashWithIndifferentAccess.new(value)
285
287
 
286
288
  required = options[:required] || []
@@ -5,7 +5,7 @@ class Glib::JsonUi::ActionBuilder
5
5
  action :onDetect
6
6
  end
7
7
 
8
- class DetectTimeZoe < Action
8
+ class DetectTimezone < Action
9
9
  action :onDetect
10
10
  end
11
11
  end
@@ -13,10 +13,12 @@ class Glib::JsonUi::ActionBuilder
13
13
  end
14
14
 
15
15
  class Remove < Action
16
+ string :key
16
17
  action :onRemove
17
18
  end
18
19
 
19
20
  class Clear < Action
21
+ string :key
20
22
  action :onClear
21
23
  end
22
24
  end
@@ -11,6 +11,7 @@ class Glib::JsonUi::ActionBuilder
11
11
 
12
12
  class Open < Action
13
13
  string :url, cache: true
14
+ bool :updateExisting
14
15
  action :onOpen
15
16
  end
16
17
 
@@ -19,7 +20,7 @@ class Glib::JsonUi::ActionBuilder
19
20
  end
20
21
 
21
22
  class Reload < Action
22
- string :url, cache: true
23
+ string :url, cache: true # deprecated
23
24
  bool :disableDirtyCheck
24
25
  action :onReload
25
26
  end
@@ -150,12 +150,16 @@ module Glib
150
150
  end
151
151
 
152
152
  # FUTURE
153
- # class Remove < Action
154
- # end
153
+ class Remove < Action
154
+ string :key
155
+ action :onRemove
156
+ end
155
157
 
156
158
  # FUTURE
157
- # class Clear < Action
158
- # end
159
+ class Clear < Action
160
+ string :key
161
+ action :onClear
162
+ end
159
163
  end
160
164
  end
161
165
  end
@@ -8,31 +8,31 @@ module Glib
8
8
  action :onMouseLeave
9
9
  end
10
10
 
11
- def tooltip(options)
12
- return unless options
11
+ # def tooltip(options)
12
+ # return unless options
13
13
 
14
- if !Rails.env.test?
15
- key = "tooltip_#{SecureRandom.uuid}"
16
- else
17
- key = 'tooltip_test'
18
- end
19
- onMouseEnter ->(action) do
14
+ # if !Rails.env.test?
15
+ # key = "tooltip_#{SecureRandom.uuid}"
16
+ # else
17
+ # key = 'tooltip_test'
18
+ # end
19
+ # onMouseEnter ->(action) do
20
20
 
21
- action.popovers_show(
22
- key: key,
23
- placement: options[:placement] || 'top',
24
- content: ->(popover) do
25
- popover.body childViews: ->(view) {
26
- view.p styleClass: 'tooltip', text: options[:text]
27
- }
28
- end
29
- )
30
- end
21
+ # action.popovers_show(
22
+ # key: key,
23
+ # placement: options[:placement] || 'top',
24
+ # content: ->(popover) do
25
+ # popover.body childViews: ->(view) {
26
+ # view.p styleClass: 'tooltip', text: options[:text]
27
+ # }
28
+ # end
29
+ # )
30
+ # end
31
31
 
32
- onMouseLeave ->(action) do
33
- action.popovers_close key: key
34
- end
35
- end
32
+ # onMouseLeave ->(action) do
33
+ # action.popovers_close key: key
34
+ # end
35
+ # end
36
36
  end
37
37
  end
38
38
  end
@@ -9,6 +9,7 @@ module Glib
9
9
  include Builder::MouseEvents
10
10
 
11
11
  hash :analytics, optional: [:featured, :disabled]
12
+ hash :tooltip, required: [:text], optional: [:placement, :position]
12
13
  end
13
14
 
14
15
  class Button < MenuItem
@@ -301,6 +301,7 @@ class Glib::JsonUi::ViewBuilder
301
301
  string :truncateLine
302
302
  end
303
303
 
304
+ # deprecated
304
305
  class Table < View
305
306
  hash :nextPage
306
307
  hash :export, required: [:label, :fileName]
@@ -325,6 +326,104 @@ class Glib::JsonUi::ViewBuilder
325
326
  end
326
327
  end
327
328
 
329
+ class BulkEdit2 < View
330
+ attr_reader :template
331
+
332
+ hash :export, required: [:label, :fileName]
333
+ hash :import, required: [:submitUrl, :paramName]
334
+
335
+ action :onLoadRows
336
+ action :onCellChange
337
+
338
+ string :paramNameForFormData
339
+
340
+ array :viewHeaders
341
+ action :onRowSelected
342
+
343
+ def initialize(json, page)
344
+ super
345
+ @template = Glib::JsonUi::TableBuilders::Template.new(json, self)
346
+ end
347
+
348
+ # Experimental
349
+ panels_builder :accessory, :header, :footer
350
+
351
+ def viewCells(values)
352
+ json.set! 'viewCells' do
353
+ values.each do |value|
354
+ value.call(page.view_builder)
355
+ end
356
+ end
357
+ end
358
+
359
+ def header(options = {})
360
+ json.header do
361
+ json.backgroundColor options.delete(:backgroundColor)
362
+ json.cellViews do
363
+ options.delete(:cellViews)&.call page.view_builder
364
+ end
365
+
366
+ json.colSpans options.delete(:colSpans)
367
+ end
368
+
369
+ raise "Invalid properties: #{options.keys}" if options.size > 0
370
+ end
371
+
372
+ def rows(options = {})
373
+ block = options.delete(:builder)
374
+ json.rows do
375
+ if (objects = options.delete(:objects))
376
+ objects.each_with_index do |object, index|
377
+ block&.call template, object, index
378
+ end
379
+ else
380
+ block&.call template
381
+ end
382
+ end
383
+
384
+ raise "Invalid properties: #{options.keys}" if options.size > 0
385
+ end
386
+
387
+ def dataRows(value)
388
+ json.dataRows value
389
+ end
390
+
391
+ def viewRows(value)
392
+ json.viewRows value
393
+ end
394
+
395
+ end
396
+
397
+ # deprecated
398
+ class BulkEdit < View
399
+ hash :nextPage
400
+ hash :export, required: [:label, :fileName]
401
+ hash :import, required: [:submitUrl, :paramName]
402
+ action :onScrollToTop
403
+ action :onScrollToBottom
404
+ string :statusViewIdPrefix
405
+ action :onLoadRows
406
+
407
+ # Experimental
408
+ panels_builder :accessory, :header, :footer
409
+
410
+ def firstSection(block)
411
+ json.sections [1] do
412
+ block.call page.table_section_builder
413
+ end
414
+ end
415
+
416
+ def sections(blocks)
417
+ json.sections do
418
+ blocks.each do |block|
419
+ json.child! do
420
+ block.call page.table_section_builder
421
+ end
422
+ end
423
+ end
424
+ end
425
+ end
426
+
328
427
  class Scroll < View
329
428
  views :childViews
330
429
  end
@@ -68,6 +68,8 @@ module Glib
68
68
  hash :analytics, optional: [:featured, :disabled]
69
69
  hash :dragData
70
70
 
71
+ hash :tooltip, required: [:text], optional: [:placement, :position]
72
+
71
73
  def self.component_name
72
74
  @component_name ||= self.name.sub('Glib::JsonUi::ViewBuilder::', '')
73
75
  end
@@ -9,4 +9,14 @@ section.rows builder: ->(template) do
9
9
  subaction.snackbars_alert message: 'Saved'
10
10
  end
11
11
  end
12
+ template.thumbnail title: 'cookies/remove', onClick: ->(action) do
13
+ action.cookies_remove key: 'glib_cookie', onRemove: ->(subaction) do
14
+ subaction.snackbars_alert message: 'Saved'
15
+ end
16
+ end
17
+ template.thumbnail title: 'cookies/clear', onClick: ->(action) do
18
+ action.cookies_clear key: 'glib_cookie', onClear: ->(subaction) do
19
+ subaction.snackbars_alert message: 'Saved'
20
+ end
21
+ end
12
22
  end
@@ -0,0 +1,16 @@
1
+ section.header padding: glib_json_padding_list, childViews: ->(header) do
2
+ header.h3 text: 'Detects'
3
+ end
4
+
5
+ section.rows builder: ->(template) do
6
+ template.thumbnail title: 'Detect Timezone', onClick: ->(action) do
7
+ action.browsers_detectTimezone onDetect: ->(detect) do
8
+ detect.http_post url: json_ui_garage_url(path: 'forms/generic_post_all')
9
+ end
10
+ end
11
+ template.thumbnail title: 'Detect Country', onClick: ->(action) do
12
+ action.browsers_detectCountry onDetect: ->(detect) do
13
+ detect.http_post url: json_ui_garage_url(path: 'forms/generic_post_all')
14
+ end
15
+ end
16
+ end
@@ -25,5 +25,9 @@ panel.panels_list id: 'action_list', sections: [
25
25
  render "#{@path_prefix}/actions/fields", section: section
26
26
  end, ->(section) do
27
27
  render "#{@path_prefix}/actions/cookies", section: section
28
+ end, ->(section) do
29
+ render "#{@path_prefix}/actions/detects", section: section
30
+ end, ->(section) do
31
+ render "#{@path_prefix}/actions/storage_item", section: section
28
32
  end
29
33
  ]
@@ -0,0 +1,27 @@
1
+
2
+ section.header padding: glib_json_padding_list, childViews: ->(header) do
3
+ header.h3 id: 'storage_items', text: 'Storage Items'
4
+ end
5
+
6
+ section.rows builder: ->(template) do
7
+ template.thumbnail title: 'storage/Set', onClick: ->(action) do
8
+ action.storageItems_set key: 'glib_storage', value: "test_storage_#{DateTime.current.to_i}", onSet: ->(subaction) do
9
+ subaction.snackbars_alert message: 'Saved'
10
+ end
11
+ end
12
+ template.thumbnail title: 'storage/Get', onClick: ->(action) do
13
+ action.storageItems_get key: 'glib_storage', onGet: ->(subaction) do
14
+ subaction.http_post url: json_ui_garage_url(path: 'forms/generic_post_all')
15
+ end
16
+ end
17
+ template.thumbnail title: 'storage/remove', onClick: ->(action) do
18
+ action.storageItems_remove key: 'glib_storage', onRemove: ->(subaction) do
19
+ subaction.snackbars_alert message: 'Saved'
20
+ end
21
+ end
22
+ template.thumbnail title: 'storage/clear', onClick: ->(action) do
23
+ action.storageItems_clear key: 'glib_storage', onClear: ->(subaction) do
24
+ subaction.snackbars_alert message: 'Saved'
25
+ end
26
+ end
27
+ end
@@ -14,6 +14,10 @@ section.rows builder: ->(template) do
14
14
  action.windows_open url: json_ui_garage_url(path: 'home/blank')
15
15
  end
16
16
 
17
+ template.thumbnail title: 'windows/open (updateExisting: true)', onClick: ->(action) do
18
+ action.windows_open updateExisting: true, url: json_ui_garage_url(path: 'home/blank')
19
+ end
20
+
17
21
  template.thumbnail title: 'windows/closeAllWithOpen', onClick: ->(action) do
18
22
  action.windows_closeAllWithOpen url: json_ui_garage_url(path: 'home/index')
19
23
 
@@ -0,0 +1,17 @@
1
+ json_ui_response json do |action|
2
+ action.runMultiple childActions: ->(multiple) do
3
+ render "#{@path_prefix}/forms/alert_post_data", action: multiple
4
+
5
+ status_view_id = "row_status_#{params[:_index]}"
6
+ # TODO: This doesn't work. It should update the status icon to indicate that the
7
+ # import is successful.
8
+ multiple.components_set \
9
+ targetId: status_view_id,
10
+ data: {
11
+ color: 'success',
12
+ material: {
13
+ name: 'check'
14
+ }
15
+ }
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ json_ui_response json do |action|
2
+ action.runMultiple childActions: ->(multiple) do
3
+ # render "#{@path_prefix}/forms/alert_post_data", action: multiple
4
+
5
+ status_cell = params[:user]['columns'][0]['compId']
6
+
7
+ multiple.components_set \
8
+ targetId: status_cell,
9
+ data: {
10
+ styleClasses: ['success'],
11
+ material: {
12
+ name: 'verified'
13
+ }
14
+ }
15
+ end
16
+ end
@@ -27,7 +27,7 @@ page.form url: json_ui_garage_url(path: 'forms/generic_post'), method: 'post', p
27
27
  template.spacer height: 10
28
28
  template.fields_text width: 'matchParent', name: 'question', label: 'Question', placeholder: 'Question'
29
29
 
30
- form.panels_responsive childViews: ->(column) do
30
+ form.panels_responsive id: 'responsive_{{entry_index}}', childViews: ->(column) do
31
31
  options = [:rating, :yes_no]
32
32
  template.fields_select \
33
33
  width: 'matchParent',
@@ -35,22 +35,45 @@ page.form url: json_ui_garage_url(path: 'forms/generic_post'), method: 'post', p
35
35
  label: 'Answer Type',
36
36
  placeholder: 'Answer Type',
37
37
  options: options.map { |o| { text: o.to_s.humanize, value: o } },
38
- onChange: ->(action) do
39
- action.components_findClosest view: 'panels/responsive', onFind: ->(find) do
40
- find.logics_set dataBuilder: ->(set) do
41
- set.panels_responsive accessory: ->(accessory) do
42
- accessory.footer childViews: ->(footer) do
43
- # TODO: Is there a way to only show this if the selected option is "rating".
44
- # I.e. `showIf: { "==": [{ "var": 'user[evaluation][{{index}}][type]' }, 'rating'] }`
45
- footer.fields_check \
46
- width: 'matchParent',
47
- name: 'enabled',
48
- label: 'Enable',
49
- checkValue: '1'
50
- end
38
+ onChangeAndLoad: ->(action) do
39
+ action.logics_set targetId: 'responsive_{{entry_index}}', dataBuilder: ->(set) do
40
+ set.panels_responsive accessory: ->(accessory) do
41
+ accessory.footer childViews: ->(footer) do
42
+ # TODO: Is there a way to only show this if the selected option is "rating".
43
+ # I.e. `showIf: { "==": [{ "var": 'user[evaluation][{{index}}][type]' }, 'rating'] }`
44
+ footer.fields_check \
45
+ width: 'matchParent',
46
+ id: 'check_{{entry_index}}',
47
+ name: 'enabled',
48
+ label: 'Enable',
49
+ checkValue: true
51
50
  end
52
51
  end
52
+ end, onSet: ->(subaction) do
53
+ subaction.logics_set \
54
+ targetId: 'check_{{entry_index}}',
55
+ conditionalData: {
56
+ value: {
57
+ "==": [{ "var": 'user[evaluation][{{entry_index}}][type]' }, 'rating']
58
+ }
59
+ }
53
60
  end
61
+
62
+ # action.components_findClosest view: 'panels/responsive', onFind: ->(find) do
63
+ # find.logics_set dataBuilder: ->(set) do
64
+ # set.panels_responsive accessory: ->(accessory) do
65
+ # accessory.footer childViews: ->(footer) do
66
+ # # TODO: Is there a way to only show this if the selected option is "rating".
67
+ # # I.e. `showIf: { "==": [{ "var": 'user[evaluation][{{index}}][type]' }, 'rating'] }`
68
+ # footer.fields_check \
69
+ # width: 'matchParent',
70
+ # name: 'enabled',
71
+ # label: 'Enable',
72
+ # checkValue: '1'
73
+ # end
74
+ # end
75
+ # end
76
+ # end
54
77
  end
55
78
  end, accessory: ->(accessory) do
56
79
  accessory.footer childViews: ->(footer) do
@@ -23,7 +23,7 @@ page.list firstSection: ->(section) do
23
23
  menu.button \
24
24
  styleClasses: ['icon', 'text', 'x-small'],
25
25
  icon: 'share',
26
- tooltip: { text: 'Share', location: 'left' }
26
+ tooltip: { text: 'Share', placement: 'left' }
27
27
 
28
28
  # TODO: Use popoever
29
29
  # childButtons: ->(submenu) do
@@ -61,7 +61,7 @@ json_ui_page json do |page|
61
61
 
62
62
  scroll.label text: "\n"
63
63
  scroll.h1 text: 'Click action'
64
- scroll.panels_vertical width: 100, height: 100, backgroundColor: '#b3bac2', align: 'center', onClick: ->(action) do
64
+ scroll.panels_vertical styleClasses: ['rounded-corner'], width: 100, height: 100, backgroundColor: '#b3bac2', align: 'center', onClick: ->(action) do
65
65
  action.windows_open url: json_ui_garage_url(path: 'home/blank')
66
66
  end, childViews: ->(panel) do
67
67
  panel.label text: 'Click me'
@@ -0,0 +1,101 @@
1
+ json.title 'Tables'
2
+
3
+ page = json_ui_page json
4
+ render "#{@path_prefix}/nav_menu", json: json, page: page
5
+
6
+ # submit_button_id = 'save_button_top'
7
+
8
+ page.scroll childViews: ->(scroll) do
9
+ # scroll.panels_bulkEdit \
10
+ # import: { submitUrl: json_ui_garage_url(path: 'forms/bulk_edit_post'), paramName: 'user' },
11
+ # statusViewIdPrefix: 'row_status_',
12
+ # firstSection: ->(section) do
13
+ # section.header cellViews: ->(header) do
14
+ # header.label text: 'month'
15
+ # header.label text: 'electricity_usage'
16
+ # header.label text: 'gas_usage'
17
+ # end
18
+ # end,
19
+ # accessory: ->(accessory) do
20
+ # accessory.header childViews: ->(header) do
21
+ # header.button \
22
+ # text: 'Save',
23
+ # id: submit_button_id,
24
+ # displayed: false,
25
+ # onClick: ->(action) do
26
+ # action.forms_submit
27
+ # end
28
+ # end
29
+ # end,
30
+ # onLoadRows: ->(action) do
31
+ # action.components_set targetId: submit_button_id, data: { displayed: true }
32
+ # end
33
+
34
+ options = [{ text: 'yes', value: 'yes' }, { text: 'no', value: 'no' }]
35
+ # scroll.button id: 'btn-action', text: 'verify', onClick: ->(action) do
36
+ # action.windows_reload url: json_ui_garage_current_url(icon: 'verified')
37
+ # end
38
+ scroll.button displayed: false, id: 'submit_top', text: 'submit', onClick: ->(action) do
39
+ action.forms_submit targetId: 'bulkEdit'
40
+ end
41
+ scroll.panels_responsive styleClass: 'overflow-y-auto', width: 'matchParent', height: 500, childViews: ->(wres) do
42
+ scroll.panels_bulkEdit2 \
43
+ id: 'bulkEdit',
44
+ width: 'matchParent',
45
+ backgroundColor: '#e2e2e2',
46
+ import: { submitUrl: json_ui_garage_url(path: 'forms/bulk_edit_post2'), paramName: 'user' },
47
+ viewHeaders: [
48
+ { text: '', id: 'status', minWidth: 24 },
49
+ { text: 'Month', id: 'month', importable: true },
50
+ { text: 'Electricity usage', id: 'electricity_usage', importable: true },
51
+ { text: 'Gas usage', id: 'gas_usage', importable: true },
52
+ { text: 'Compliant', id: 'compliant', importable: true }
53
+ ],
54
+ viewCells: [
55
+ ->(view) do
56
+ view.icon name: params[:icon] || 'preview', styleClasses: ['warning'], tooltip: { text: params[:icon] || 'preview' }
57
+ end,
58
+ ->(view) do
59
+ view.fields_number width: 100
60
+ end,
61
+ ->(view) do
62
+ view.fields_number width: 150
63
+ end,
64
+ ->(view) do
65
+ view.fields_number width: 100
66
+ end,
67
+ ->(view) do
68
+ view.fields_select options: options
69
+ end
70
+ ],
71
+ paramNameForFormData: 'message',
72
+ onCellChange: ->(action) do
73
+ action.snackbars_alert
74
+ end,
75
+ onLoadRows: ->(action) do
76
+ action.runMultiple childActions: ->(multiple) do
77
+ multiple.snackbars_alert message: 'rows loaded'
78
+ multiple.components_set targetId: 'submit_top', data: { displayed: true }
79
+ multiple.components_set targetId: 'submit_bottom', data: { displayed: true }
80
+ end
81
+ end
82
+ # onRowSelected: ->(action) do
83
+ # action.snackbars_alert
84
+ # end
85
+ # dataRows: [
86
+ # { rowId: 1, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 1 }, { value: 30 }, { value: 33 }, { value: 'yes' }] },
87
+ # { rowId: 2, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 2 }, { value: 34 }, { value: 35 }, { value: 'no' }] },
88
+ # { rowId: 3, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 1 }, { value: 30 }, { value: 33 }, { value: 'yes' }] },
89
+ # { rowId: 4, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 2 }, { value: 34 }, { value: 35 }, { value: 'no' }] },
90
+ # { rowId: 5, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 1 }, { value: 30 }, { value: 33 }, { value: 'yes' }] },
91
+ # { rowId: 6, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 2 }, { value: 34 }, { value: 35 }, { value: 'no' }] },
92
+ # { rowId: 7, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 1 }, { value: 30 }, { value: 33 }, { value: 'yes' }] },
93
+ # { rowId: 8, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 2 }, { value: 34 }, { value: 35 }, { value: 'no' }] },
94
+ # { rowId: 9, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 1 }, { value: 30 }, { value: 33 }, { value: 'yes' }] },
95
+ # { rowId: 10, columns: [{ material: { name: params[:icon] || 'preview' }, value: 'preview' }, { value: 2 }, { value: 34 }, { value: 35 }, { value: 'no' }] }
96
+ # ]
97
+ end
98
+ scroll.button displayed: false, id: 'submit_bottom', text: 'submit', onClick: ->(action) do
99
+ action.forms_submit targetId: 'bulkEdit'
100
+ end
101
+ end
@@ -11,9 +11,6 @@ page.list firstSection: ->(section) do
11
11
  template.thumbnail title: 'Horizontal Scroll', onClick: ->(action) do
12
12
  action.windows_open url: json_ui_garage_url(path: 'tables/horizontal_scroll')
13
13
  end
14
- template.thumbnail title: 'Export/Import', onClick: ->(action) do
15
- action.windows_open url: json_ui_garage_url(path: 'tables/export_import')
16
- end
17
14
  template.thumbnail title: 'Autoload as Needed', onClick: ->(action) do
18
15
  action.windows_open url: json_ui_garage_url(path: 'tables/autoload_as_needed')
19
16
  end
@@ -23,6 +20,12 @@ page.list firstSection: ->(section) do
23
20
  template.thumbnail title: 'Panel Content', onClick: ->(action) do
24
21
  action.windows_open url: json_ui_garage_url(path: 'tables/panel_content')
25
22
  end
23
+ template.thumbnail title: 'Export/Import (Maybe deprecated in the future)', onClick: ->(action) do
24
+ action.windows_open url: json_ui_garage_url(path: 'tables/export_import')
25
+ end
26
+ template.thumbnail title: 'Bulk edit and import', onClick: ->(action) do
27
+ action.windows_open url: json_ui_garage_url(path: 'tables/bulk_edit')
28
+ end
26
29
  end
27
30
 
28
31
  end
@@ -63,6 +63,12 @@ page.body padding: glib_json_padding_body, childViews: ->(body) do
63
63
  view.fields_select options: cities + [{ text: 'Taipei', value: 'taipei' }]
64
64
  end
65
65
  end
66
+
67
+ hori.button text: 'Change icon', onClick: ->(action) do
68
+ action.components_replace targetId: 'icon', newView: ->(view) do
69
+ view.icon name: 'verified', styleClasses: ['success']
70
+ end
71
+ end
66
72
  end
67
73
  res.spacer height: 16
68
74
  res.h3 text: 'Childviews changes'
@@ -103,7 +109,7 @@ page.body padding: glib_json_padding_body, childViews: ->(body) do
103
109
 
104
110
  res.panels_column lg: { cols: 9 }, childViews: ->(col) do
105
111
  col.panels_responsive id: 'pres', width: 200, childViews: ->(cview) do
106
- cview.label text: 'Panels responsive'
112
+ cview.label text: 'Panels responsive', id: 'text-responsive'
107
113
  end
108
114
  col.spacer height: 4
109
115
  col.panels_column id: 'pcol', lg: { cols: 6 }, childViews: ->(cview) do
@@ -143,6 +149,8 @@ page.body padding: glib_json_padding_body, childViews: ->(body) do
143
149
  col.spacer height: 4
144
150
  col.fields_submit text: 'Submit'
145
151
  end
152
+ col.spacer height: 8
153
+ col.icon id: 'icon', name: 'pending', size: 32, styleClasses: ['warning']
146
154
  end
147
155
  end
148
156
  end
@@ -81,7 +81,7 @@ page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
81
81
  scroll.button \
82
82
  icon: 'info',
83
83
  styleClasses: ['icon', 'plain'],
84
- tooltip: { text: 'Disabled Icon button with tooltip text and custom tooltip position', position: 'right' },
84
+ tooltip: { text: 'Disabled Icon button with tooltip text and custom tooltip position', placement: 'right' },
85
85
  disabled: true
86
86
 
87
87
  scroll.spacer height: 20
@@ -1,22 +1,38 @@
1
1
  module Glib
2
2
  module JsonCrawler
3
3
  class FormsSubmit < ActionCrawler
4
- def initialize(http, form)
4
+ def initialize(http, args)
5
5
  super(http)
6
6
 
7
- raise 'Submit action needs to be inside a form' unless form
7
+ return if http.router.should_defer_crawl?(self, args)
8
8
 
9
- @http = http
9
+ form = http.router.last_form
10
+ execute(form)
11
+ end
10
12
 
11
- method = form['method']
12
- action = "forms/#{method}"
13
+ def execute(form)
14
+ http = @http
13
15
 
14
- case method
15
- when 'patch', 'put', 'post'
16
- submit_form(form, action, method.to_sym)
16
+ raise "Submit action needs to be inside a form: #{http.router.last_log}" unless form
17
+
18
+ case form['view']
19
+ when 'panels/bulkEdit2-v1'
20
+ method = 'post'
21
+ action = "forms/#{method}"
22
+ url = form['import']['submitUrl']
23
+ # TODO: Simulate data submission and check response
24
+ @http.router.log action, url
17
25
  else
18
- url = form['url']
19
- http.router.log action, url
26
+ method = form['method']
27
+ action = "forms/#{method}"
28
+
29
+ case method
30
+ when 'patch', 'put', 'post'
31
+ submit_form(form, action, method.to_sym)
32
+ else
33
+ url = form['url']
34
+ http.router.log action, url
35
+ end
20
36
  end
21
37
  end
22
38
 
@@ -1,25 +1,48 @@
1
1
  module Glib
2
2
  module JsonCrawler
3
3
  class Router
4
- attr_reader :read_only_actions, :logger
4
+ attr_reader :read_only_actions, :logger, :last_log, :deferred_actions
5
5
  attr_accessor :host
6
6
 
7
7
  def log(action, url, response = nil)
8
- @logger += ' ' * @depth + [
8
+ @last_log = [
9
9
  action,
10
10
  response.present? ? response.code : nil,
11
11
  url
12
- ].compact.join(' :: ') + "\n"
12
+ ].compact.join(' :: ')
13
+
14
+ # puts @last_log
15
+
16
+ @logger += ' ' * @depth + @last_log + "\n"
13
17
  end
14
18
 
15
19
  def _puts(text)
16
20
  puts ' ' * @depth + text
17
21
  end
18
22
 
23
+ def assert_target_ids_exist(args)
24
+ if (target_ids = args['targetIds'])
25
+ target_ids.each do |target_id|
26
+ @visitor.defer_action(nil, target_id)
27
+ end
28
+ elsif (target_id = args['targetId'])
29
+ @visitor.defer_action(nil, target_id)
30
+ end
31
+ end
32
+
33
+ def should_defer_crawl?(action_crawler, args)
34
+ if (target_id = args['targetId'])
35
+ @visitor.defer_action(action_crawler, target_id)
36
+ return true
37
+ end
38
+
39
+ false
40
+ end
41
+
19
42
  def initialize
20
43
  @depth = -1
21
44
  @logger = ''
22
- @visitor = Glib::Json::Traversal::Visitor.new
45
+ @visitor = Glib::Json::Traversal::Visitor.new(crawler_test: true)
23
46
  @read_only_actions = Set.new
24
47
  # default rails's development host
25
48
  @host ||= 'localhost:3000'
@@ -32,8 +55,9 @@ module Glib
32
55
  case args['view']
33
56
  when 'fields/submit-v1', 'fields/submit'
34
57
  @depth += 1
35
- forms = @visitor.forms
36
- JsonCrawler::FormsSubmit.new(http, forms.last)
58
+ # forms = @visitor.forms
59
+ # JsonCrawler::FormsSubmit.new(http, args, forms.last)
60
+ JsonCrawler::FormsSubmit.new(http, args)
37
61
  @depth -= 1
38
62
  return
39
63
  end
@@ -51,6 +75,8 @@ module Glib
51
75
  action = spec&.fetch('action')
52
76
  params = spec
53
77
 
78
+ assert_target_ids_exist(params)
79
+
54
80
  if action.present?
55
81
  @depth += 1
56
82
  case action
@@ -74,8 +100,9 @@ module Glib
74
100
  when 'http/post-v1', 'http/post'
75
101
  JsonCrawler::ActionHttp.new(:post, http, params, action)
76
102
  when 'forms/submit-v1', 'forms/submit'
77
- forms = @visitor.forms
78
- JsonCrawler::FormsSubmit.new(http, forms.last)
103
+ # forms = @visitor.forms
104
+ # JsonCrawler::FormsSubmit.new(http, params, forms.last)
105
+ JsonCrawler::FormsSubmit.new(http, params)
79
106
  when 'dialogs/alert-v1', 'dialogs/alert'
80
107
  JsonCrawler::DialogsAlert.new(http, params, action)
81
108
  else
@@ -93,6 +120,10 @@ module Glib
93
120
  end
94
121
  end
95
122
 
123
+ def last_form
124
+ @visitor.forms.last
125
+ end
126
+
96
127
  def follow(http, target_routers)
97
128
  if !target_routers.is_a?(Array)
98
129
  target_routers = [target_routers]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glib-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.8.1
4
+ version: 4.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
@@ -163,6 +163,7 @@ files:
163
163
  - app/views/json_ui/garage/actions/_commands.json.jbuilder
164
164
  - app/views/json_ui/garage/actions/_components.json.jbuilder
165
165
  - app/views/json_ui/garage/actions/_cookies.json.jbuilder
166
+ - app/views/json_ui/garage/actions/_detects.json.jbuilder
166
167
  - app/views/json_ui/garage/actions/_dialogs.json.jbuilder
167
168
  - app/views/json_ui/garage/actions/_dialogs_show.json.jbuilder
168
169
  - app/views/json_ui/garage/actions/_fields.json.jbuilder
@@ -172,6 +173,7 @@ files:
172
173
  - app/views/json_ui/garage/actions/_reload.json.jbuilder
173
174
  - app/views/json_ui/garage/actions/_sheets.json.jbuilder
174
175
  - app/views/json_ui/garage/actions/_snackbars.json.jbuilder
176
+ - app/views/json_ui/garage/actions/_storage_item.jbuilder
175
177
  - app/views/json_ui/garage/actions/_timeouts.json.jbuilder
176
178
  - app/views/json_ui/garage/actions/_tours.json.jbuilder
177
179
  - app/views/json_ui/garage/actions/_windows.json.jbuilder
@@ -186,6 +188,8 @@ files:
186
188
  - app/views/json_ui/garage/forms/_read_more_text.json.jbuilder
187
189
  - app/views/json_ui/garage/forms/basic.json.jbuilder
188
190
  - app/views/json_ui/garage/forms/basic_post.json.jbuilder
191
+ - app/views/json_ui/garage/forms/bulk_edit_post.json.jbuilder
192
+ - app/views/json_ui/garage/forms/bulk_edit_post2.json.jbuilder
189
193
  - app/views/json_ui/garage/forms/checkboxes.json.jbuilder
190
194
  - app/views/json_ui/garage/forms/chip_group.json.jbuilder
191
195
  - app/views/json_ui/garage/forms/conditional_value.json.jbuilder
@@ -288,6 +292,7 @@ files:
288
292
  - app/views/json_ui/garage/tables/_autoload_section.json.jbuilder
289
293
  - app/views/json_ui/garage/tables/autoload_all.json.jbuilder
290
294
  - app/views/json_ui/garage/tables/autoload_as_needed.json.jbuilder
295
+ - app/views/json_ui/garage/tables/bulk_edit.json.jbuilder
291
296
  - app/views/json_ui/garage/tables/export_import.json.jbuilder
292
297
  - app/views/json_ui/garage/tables/horizontal_scroll.json.jbuilder
293
298
  - app/views/json_ui/garage/tables/index.json.jbuilder