glib-web 4.8.1 → 4.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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