glib-web 0.5.0 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/glib/home_controller.rb +1 -1
  3. data/app/helpers/glib/app_feature_support_helper.rb +16 -0
  4. data/app/helpers/glib/json_ui/list_builders.rb +5 -0
  5. data/app/helpers/glib/json_ui/page_helper.rb +21 -16
  6. data/app/helpers/glib/json_ui/view_builder/fields.rb +3 -0
  7. data/app/helpers/glib/json_ui/view_builder/panels.rb +2 -0
  8. data/app/views/json_ui/garage/actions/_dialogs.json.jbuilder +21 -12
  9. data/app/views/json_ui/garage/actions/dialogs_oauth_post.json.jbuilder +6 -0
  10. data/app/views/json_ui/garage/forms/dynamic_group.json.jbuilder +9 -18
  11. data/app/views/json_ui/garage/forms/dynamic_select_data.json.jbuilder +25 -10
  12. data/app/views/json_ui/garage/forms/file_upload.json.jbuilder +5 -5
  13. data/app/views/json_ui/garage/forms/pickers.json.jbuilder +6 -3
  14. data/app/views/json_ui/garage/lists/_infinite_scroll_section.json.jbuilder +15 -5
  15. data/app/views/json_ui/garage/notifications/index.json.jbuilder +0 -43
  16. data/app/views/json_ui/garage/notifications/web_socket.json.jbuilder +19 -21
  17. data/app/views/json_ui/garage/tables/autoload_as_needed.json.jbuilder +39 -0
  18. data/app/views/json_ui/garage/tables/index.json.jbuilder +3 -0
  19. data/app/views/json_ui/garage/views/_chart_data.json.jbuilder +1 -1
  20. data/app/views/json_ui/garage/views/calendar_data.json.jbuilder +23 -27
  21. data/lib/glib-web.rb +1 -0
  22. data/lib/glib/json_crawler.rb +1 -0
  23. data/lib/glib/json_crawler/action_crawlers/menu.rb +12 -0
  24. data/lib/glib/json_crawler/action_crawlers/nav_initiate.rb +1 -1
  25. data/lib/glib/json_crawler/action_crawlers/windows_open.rb +8 -3
  26. data/lib/glib/json_crawler/http.rb +14 -14
  27. data/lib/glib/json_crawler/router.rb +3 -6
  28. data/lib/glib/test_helpers.rb +40 -0
  29. metadata +6 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 832af08d8701c658362e9974f4a9ed5a52c5bb5f
4
- data.tar.gz: 81b729e8cc79ee02437eb96b715ad8e4ccd86283
3
+ metadata.gz: 3a631905663a326cc5d4da2aa0be179812d12aae
4
+ data.tar.gz: a167fd02e4db101e5067832225762ba410bc401b
5
5
  SHA512:
6
- metadata.gz: 2ee4d1c3b862f97349c17d9d638766006ad47832b26b7abc46d8976139012f1ab2fbe23bf931c0fc36623f06c7a7ae8802e8d766044c9c11a4194a8684214875
7
- data.tar.gz: 1d76aa4197f3d12d3131b3224e83d76fe7d8c3aa54a8a258945ca2f76f8b690ef4f281d3d961d3a9b785c8660bb6d66a9ccb45ebc1494a57e2b53162df512ce2
6
+ metadata.gz: 0a5094637dbe44532c384bd7e30a49bb3dd5377ef87cee6ea13da3528620aae8f2a43eba21f3077df4530a3356087851dcbd8be150d72a3ff1af70b4b3493afb
7
+ data.tar.gz: 03b85596d99b043700a6818feef54b6e45017e905800358502052a68bdf0d6cb472c64bc9bb352849a9628b587479bfbab41314da1543cb1f92317371639ac07
@@ -1,6 +1,6 @@
1
1
  module Glib
2
2
  class HomeController < ApplicationController
3
- if glib_auth_inited?
3
+ if try(:glib_auth_inited?)
4
4
  skip_before_action :glib_load_resource
5
5
  skip_before_action :glib_authorize_resource
6
6
  end
@@ -0,0 +1,16 @@
1
+ module Glib
2
+ module AppFeatureSupportHelper
3
+ def glib_app_feature_supported?(name, app_version, dictionary)
4
+ device = (app_device_os || :default).to_sym
5
+
6
+ version = dictionary[name.to_sym].try(:[], device)
7
+ except = dictionary[name.to_sym].try(:[], :except).try(:[], device)
8
+
9
+ !version.nil? && (version == :all || glib_app_version_gte(version, app_version)) && (except.nil? || except.to_s != app_version)
10
+ end
11
+
12
+ def glib_app_version_gte(feature_version, app_version)
13
+ app_version.blank? || Gem::Version.new(app_version) >= Gem::Version.new(feature_version)
14
+ end
15
+ end
16
+ end
@@ -41,6 +41,11 @@ module Glib
41
41
 
42
42
  class Custom < Thumbnail
43
43
  string :template
44
+
45
+ # TODO: Experimental
46
+ hash :extra
47
+
48
+ # TODO: Deprecate
44
49
  hash :data
45
50
  end
46
51
  end
@@ -17,22 +17,27 @@ module Glib
17
17
  @__json_ui_page
18
18
  end
19
19
 
20
- # Use this only if you need to generate json independently from the current `json_ui_page`
21
- def json_ui_menu(&block)
22
- @__json_ui_menu_page ||= Page.new(Jbuilder.new, self)
23
- json = @__json_ui_menu_page.json
24
- json.nil!
25
- block&.call @__json_ui_menu_page.menu_builder
26
- json.attributes!
27
- end
28
-
29
- # Use this only if you need to generate json independently from the current `json_ui_page`
30
- def json_ui_panel(&block)
31
- @__json_ui_panel_page ||= Page.new(Jbuilder.new, self)
32
- json = @__json_ui_panel_page.json
33
- json.nil!
34
- block&.call @__json_ui_panel_page.view_builder
35
- json.attributes!
20
+ # # Use this only if you need to generate json independently from the current `json_ui_page`
21
+ # def json_ui_menu(&block)
22
+ # @__json_ui_menu_page ||= Page.new(Jbuilder.new, self)
23
+ # json = @__json_ui_menu_page.json
24
+ # json.nil!
25
+ # block&.call @__json_ui_menu_page.menu_builder
26
+ # json.attributes!
27
+ # end
28
+
29
+ # # Use this only if you need to generate json independently from the current `json_ui_page`
30
+ # def json_ui_panel(&block)
31
+ # @__json_ui_panel_page ||= Page.new(Jbuilder.new, self)
32
+ # json = @__json_ui_panel_page.json
33
+ # json.nil!
34
+ # block&.call @__json_ui_panel_page.view_builder
35
+ # json.attributes!
36
+ # end
37
+
38
+ def json_ui_section(json, &block)
39
+ @__json_ui_section ||= Page.new(json, self)
40
+ @__json_ui_section.list_section_builder
36
41
  end
37
42
 
38
43
  class Page
@@ -104,6 +104,9 @@ class Glib::JsonUi::ViewBuilder
104
104
 
105
105
  class Check < Text
106
106
  string :uncheckValue
107
+ string :checkValue
108
+
109
+ # Where possible, use value instead of this
107
110
  bool :checked
108
111
  end
109
112
 
@@ -123,6 +123,8 @@ class Glib::JsonUi::ViewBuilder
123
123
  hash :nextPage
124
124
  hash :export
125
125
  hash :import
126
+ action :onScrollToTop
127
+ action :onScrollToBottom
126
128
 
127
129
  def firstSection(block)
128
130
  json.sections [1] do
@@ -79,17 +79,26 @@ section.rows builder: ->(template) do
79
79
  end
80
80
 
81
81
  template.thumbnail title: 'dialogs/oauth', onClick: ->(action) do
82
- provider = {
83
- name: "facebook",
84
- webRequestUrl: "https://www.facebook.com/v3.1/dialog/oauth?auth_type=rerequest&client_id=CLIENT_ID&redirect_uri=http%3A%2F%2Fwww.lvh.me%3A3000%2Foauth_callback%2Ffacebook&response_type=code&scope=email",
85
- requestUrl: "https://www.facebook.com/v3.1/dialog/oauth",
86
- clientId: "CLIENT_ID",
87
- redirectUrl: "http://www.lvh.me:3000/oauth_callback/facebook.json"
88
- }
89
-
90
- action.dialogs_oauth provider: provider, providerParamName: "session[oauth_provider]", callbackUrlParamName: "session[[oauth_callback_url]", onSuccess: ->(action) do
91
- action.http_post url: 'TODO: post params to server'
82
+ if respond_to?(:user_facebook_omniauth_authorize_url)
83
+ provider = {
84
+ name: 'facebook',
85
+ webRequestUrl: user_facebook_omniauth_authorize_url(format: nil, _render: nil),
86
+ requestUrl: user_facebook_omniauth_authorize_url(format: nil),
87
+ clientId: Devise.omniauth_configs[:facebook].strategy[:client_id],
88
+ permissions: Devise.omniauth_configs[:facebook].strategy[:scope],
89
+ redirectUrl: user_facebook_omniauth_callback_url(format: nil)
90
+ }
91
+ action.dialogs_oauth provider: provider, providerParamName: 'session[oauth_provider]', callbackUrlParamName: 'session[[oauth_callback_url]', onSuccess: ->(subaction) do
92
+ subaction.http_post url: json_ui_garage_url(path: 'actions/dialogs_oauth_post'), formData: {
93
+ authenticity_token: form_authenticity_token
94
+ }
95
+ end
96
+ else
97
+ action.dialogs_alert message: 'To enable this, set up omniauth using devise'
98
+ # E.g.
99
+ # Add `devise :omniauthable, omniauth_providers: %i[facebook]` to user.rb
100
+ # Add `gem 'omniauth-facebook'` to Gemfile
101
+ # Add `config.omniauth :facebook` to devise.rb
92
102
  end
93
103
  end
94
-
95
- end
104
+ end
@@ -0,0 +1,6 @@
1
+ facebook_graph = Koala::Facebook::API.new(params[:credentials][:token])
2
+ profile = facebook_graph.get_object('me')
3
+
4
+ json_ui_response json do |action|
5
+ action.dialogs_alert message: profile
6
+ end
@@ -10,7 +10,8 @@ json_ui_page json do |page|
10
10
  value = [
11
11
  {
12
12
  'question': 'Punctuality',
13
- 'type': 'rating'
13
+ 'type': 'rating',
14
+ 'enabled': '1'
14
15
  },
15
16
  {
16
17
  'question': 'Quality of work',
@@ -21,30 +22,20 @@ json_ui_page json do |page|
21
22
  'type': 'yes_no'
22
23
  }
23
24
  ]
24
- # form.fields_dynamicGroup width: 'matchParent', name: 'user[evaluation]', value: value, groupTitlePrefix: 'Entry', groupTemplateViews: ->(group) do
25
- # group.spacer height: 10
26
- # group.fields_text width: 'matchParent', name: 'question', label: 'Question'
27
- # group.fields_text width: 'matchParent', name: 'type', label: 'Answer type'
28
- # end
29
-
30
- # form.fields_dynamicGroup width: 'matchParent', name: 'user[evaluation]', value: value, group: ->(group) do
31
- # group.titlePrefix 'Entry'
32
- # group.template childViews: ->(template) do
33
- # template.spacer height: 10
34
- # template.fields_text width: 'matchParent', name: 'question', label: 'Question'
35
- # template.fields_text width: 'matchParent', name: 'type', label: 'Answer type'
36
- # end
37
- # end
38
25
 
39
26
  form.fields_dynamicGroup width: 'matchParent', name: 'user[evaluation]', value: value, titlePrefix: 'Entry', content: ->(group) do
40
27
  group.template padding: { left: 32 }, childViews: ->(template) do
41
28
  template.spacer height: 10
42
- template.fields_text width: 'matchParent', name: 'question', label: 'Question'
43
- template.fields_text width: 'matchParent', name: 'type', label: 'Answer type'
29
+ template.fields_text width: 'matchParent', name: 'question', label: 'Question', placeholder: 'Question'
30
+ options = [ :rating, :yes_no ]
31
+ template.fields_select width: 'matchParent', name: 'type', label: 'Answer Type', placeholder: 'Answer Type', options: options.map { |o| { text: o.to_s.humanize, value: o } }
32
+ template.fields_check width: 'matchParent', name: 'enabled', label: 'Enable', checkValue: '1'
33
+
34
+ template.spacer height: 14
44
35
  end
45
36
  end
46
37
 
47
38
  form.spacer height: 20
48
- form.button text: 'Submit', onClick: ->(action) { action.forms_submit }
39
+ form.fields_submit text: 'Submit'
49
40
  end
50
41
  end
@@ -6,18 +6,33 @@ if page < 2
6
6
  json.nextPageUrl json_ui_garage_url(path: 'forms/dynamic_select_data', page: page + 1)
7
7
  end
8
8
 
9
- json.rows do
9
+ # json.rows do
10
10
 
11
+ # count_per_page = 20
12
+ # count_per_page.times do |i|
13
+ # json.child! do
14
+ # index = page * count_per_page + i
15
+ # json.template 'thumbnail'
16
+ # json.title "City #{index} (#{params[:q]})"
17
+ # json.subtitle "State #{index}"
18
+ # json.subsubtitle "Country #{index}"
19
+ # json.value "id#{index}"
20
+ # json.text "Item #{index}"
21
+ # end
22
+ # end
23
+ # end
24
+
25
+ section = json_ui_section json
26
+ section.rows builder: ->(row) do
11
27
  count_per_page = 20
12
28
  count_per_page.times do |i|
13
- json.child! do
14
- index = page * count_per_page + i
15
- json.template 'thumbnail'
16
- json.title "City #{index} (#{params[:q]})"
17
- json.subtitle "State #{index}"
18
- json.subsubtitle "Country #{index}"
19
- json.value "id#{index}"
20
- json.text "Item #{index}"
21
- end
29
+ index = page * count_per_page + i
30
+ row.custom title: "City #{index} (#{params[:q]})",
31
+ subtitle: "State #{index}",
32
+ subsubtitle: "Country #{index}",
33
+ extra: {
34
+ value: "id#{index}",
35
+ text: "Item #{index}"
36
+ }
22
37
  end
23
38
  end
@@ -8,18 +8,18 @@ options = {
8
8
 
9
9
  json_ui_page json do |page|
10
10
  render "#{@path_prefix}/nav_menu", json: json, page: page
11
-
11
+
12
12
  page.form options.merge(childViews: ->(form) do
13
13
  rules1 = { fileType: "image/*", maxFileSize: 5000 }
14
14
  rules2 = { fileType: "image/*", maxFileSize: 1, fileTypeErrorText: 'Invalid!', maxFileSizeErrorText: 'Too big!' }
15
- form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Photo', accepts: rules1, directUploadUrl: rails_direct_uploads_url,
15
+ form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Landscape Photo', accepts: rules1, directUploadUrl: rails_direct_uploads_url,
16
16
  value: 'eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBFQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--193dc0d939b9558fc4973fafbba91d989cbb04d4',
17
17
  fileUrl: 'https://imageserver-demo.herokuapp.com/image/itinerarybuilder-demo/o6CKzNt67PWnkPdUEnWMt7pr?h=100&w=100',
18
18
  fileTitle: '1 month ago',
19
- placeholderView: { type: 'image', width: 100, height: 100 }
19
+ placeholderView: { type: 'image', width: 100, height: 75, url: 'https://www.atms.com.au/wp-content/uploads/2019/10/placeholder-1-1024x683.png?x93630' }
20
20
 
21
- form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Photo', accepts: rules2, directUploadUrl: rails_direct_uploads_url,
22
- placeholderView: { type: 'avatar', width: 100, height: 100 }
21
+ form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Avatar', accepts: rules2, directUploadUrl: rails_direct_uploads_url,
22
+ placeholderView: { type: 'avatar', width: 100, height: 100, url: 'data:image/jpeg;base64,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' }
23
23
 
24
24
  form.fields_submit text: 'Submit'
25
25
  # form.button text: 'Submit', onClick: ->(action) { action.forms_submit }
@@ -8,14 +8,16 @@ json_ui_page json do |page|
8
8
  form.spacer height: 6
9
9
  form.h4 text: 'Gender'
10
10
  form.fields_radioGroup name: 'user[gender]', value: 'F', childViews: ->(group) do
11
+ group.fields_radio value: '', label: 'Unknown'
11
12
  group.fields_radio value: 'M', label: 'Male'
12
13
  group.fields_radio value: 'F', label: 'Female'
13
14
  end
14
15
 
15
16
  form.spacer height: 20
16
17
  form.h2 text: 'Single Checkbox'
17
- form.fields_check name: 'user[age_range]', value: '16+', uncheckValue: '0-16', label: 'I am over 16 (has default value)'
18
- form.fields_check name: 'user[employer]', value: 1, label: 'I am an employer (no default value)'
18
+ form.fields_check name: 'user[age_range]', value: '16+', checkValue: '16+', uncheckValue: '0-16', label: 'I am over 16 (has default value)'
19
+ form.fields_check name: 'user[employer]', checkValue: 1, label: 'I am an employer (no default value)'
20
+ form.fields_check name: 'user[enabled]', checkValue: true, label: 'Enable', styleClass: 'switch', value: 'true'
19
21
 
20
22
  form.spacer height: 20
21
23
  form.h2 text: 'Date/Time'
@@ -36,7 +38,8 @@ json_ui_page json do |page|
36
38
  latitudeField: { name: 'user[latitude]', label: 'Lat', value: -33.8523063, readOnly: true },
37
39
  longitudeField: { name: 'user[longitude]', label: 'Long', value: 151.21078710000006, readOnly: true }
38
40
 
39
- form.button text: 'Submit', onClick: ->(action) { action.forms_submit }
41
+ form.spacer height: 20
42
+ form.fields_submit text: 'Submit'
40
43
 
41
44
  end
42
45
 
@@ -1,10 +1,20 @@
1
- json.rows do
1
+
2
+ # json.rows do
3
+ # batch_count = 30
4
+ # batch_count.times do |i|
5
+ # index = page * batch_count + i
6
+ # json.child! do
7
+ # json.template 'thumbnail'
8
+ # json.title "Item #{index}"
9
+ # end
10
+ # end
11
+ # end
12
+
13
+ section = json_ui_section json
14
+ section.rows builder: ->(row) do
2
15
  batch_count = 30
3
16
  batch_count.times do |i|
4
17
  index = page * batch_count + i
5
- json.child! do
6
- json.template 'thumbnail'
7
- json.title "Item #{index}"
8
- end
18
+ row.thumbnail title: "Item #{index}"
9
19
  end
10
20
  end
@@ -1,23 +1,5 @@
1
1
  json.title 'Notifications'
2
2
 
3
- # json.ws({
4
- # "socket" => {
5
- # "endpoint" => "/socket/websocket",
6
- # "params" => {
7
- # "vsn": "2.0.0"
8
- # }
9
- # },
10
- # # "topic" => "room:30",
11
- # # "event" => "comments_updated",
12
- # "topic" => "links",
13
- # "event" => "new_link_added",
14
- # "header" => {
15
- # "user_id" => 2,
16
- # "prev_item_id" => nil,
17
- # "last_item_id" => nil
18
- # }
19
- # })
20
-
21
3
  page = json_ui_page json
22
4
  render "#{@path_prefix}/nav_menu", json: json, page: page, top_nav: true
23
5
 
@@ -31,31 +13,6 @@ page.list firstSection: ->(section) do
31
13
 
32
14
  template.thumbnail title: 'WebSocket Real-time Update', onClick: ->(action) do
33
15
  action.windows_open url: json_ui_garage_url(path: 'notifications/web_socket')
34
- # dialogs_notification title: 'Hello World', message: 'This is a notification', onClick: ->(subaction) do
35
- # subaction.dialogs_alert message: 'Perform action'
36
- # end
37
16
  end
38
-
39
- # template.thumbnail title: 'Send WebSocket Notification', onClick: ->(action) do
40
- # json.action "ws/push"
41
- # json.topic "links"
42
- # json.event "new_link"
43
- # json.payload({
44
- # "club_id": "2",
45
- # "room_id": "30",
46
- # "user_id": "2"
47
- # # title: "TITLE",
48
- # # url: "URL"
49
- # })
50
-
51
- # # "topic": "room:30",
52
- # # "event": "create_comment",
53
- # # "payload": {
54
- # # "club_id": "2",
55
- # # "room_id": "30",
56
- # # "user_id": "2"
57
- # # }
58
-
59
- # end
60
17
  end
61
18
  end
@@ -14,7 +14,7 @@ json.ws({
14
14
  # "topic" => "room:30",
15
15
  # "event" => "comments_updated",
16
16
  "topic" => "links",
17
- "event" => "new_link_added",
17
+ "events" => ["new_link_added"],
18
18
  "header" => {
19
19
  "user_id" => 2,
20
20
  "prev_item_id" => nil,
@@ -23,31 +23,29 @@ json.ws({
23
23
  })
24
24
 
25
25
  page.form url: json_ui_garage_url(path: 'forms/basic_post'), method: 'post', padding: glib_json_padding_body, paramNameForFormData: 'formData', onSubmit: ->(action) do
26
- # action.dialogs_alert
27
-
28
- json.action "ws/push"
29
- json.topic "links"
30
- json.event "new_link"
31
- json.payload({
32
- "club_id": "2",
33
- "room_id": "30",
34
- "user_id": "2"
35
- # title: "TITLE",
36
- # url: "URL"
37
- })
38
-
39
- # "topic": "room:30",
40
- # "event": "create_comment",
41
- # "payload": {
42
- # "club_id": "2",
43
- # "room_id": "30",
44
- # "user_id": "2"
45
- # }
26
+ json.action "ws/push"
27
+ json.topic "links"
28
+ json.event "new_link"
29
+ json.payload({
30
+ "club_id": "2",
31
+ "room_id": "30",
32
+ "user_id": "2"
33
+ # title: "TITLE",
34
+ # url: "URL"
35
+ })
46
36
 
47
37
  end, childViews: ->(form) do
38
+ form.spacer height: 14
39
+ form.label text: "Message: #{params[:message]}"
40
+ form.spacer height: 14
41
+
48
42
  form.fields_text name: 'user[name]', width: 'matchParent', label: 'Name'
43
+
44
+ # TODO: Change this to radio for selecting alert vs reload response
49
45
  form.fields_password name: 'user[password]', width: 'matchParent', label: 'Password'
50
46
 
47
+ form.fields_hidden name: 'baseUrl', width: 'matchParent', value: json_ui_garage_url(path: 'notifications/web_socket')
48
+
51
49
  form.panels_split width: 'matchParent', content: ->(split) do
52
50
  # split.left childViews: ->(left) do
53
51
  # if params[:mode] == 'dialog'
@@ -0,0 +1,39 @@
1
+
2
+ page_index = params[:page].to_i
3
+ next_page = {
4
+ url: json_ui_garage_url(path: 'tables/autoload_all', page: page_index + 1, section_only: 'v1'),
5
+ autoload: 'asNeeded'
6
+ }
7
+
8
+ column_indexes = (1..3)
9
+ if params[:section_only].present?
10
+ json.nextPage next_page if page_index < 3
11
+ json_ui_page json do |page|
12
+ json.sections do
13
+ json.child! do
14
+ render 'json_ui/garage/tables/autoload_section', page: page, page_index: page_index, column_indexes: column_indexes
15
+ end
16
+ end
17
+ end
18
+ else
19
+ json.title 'Tables'
20
+
21
+ json_ui_page json do |page|
22
+ render "#{@path_prefix}/nav_menu", json: json, page: page
23
+
24
+ page.table nextPage: next_page, firstSection: ->(section) do
25
+ section.header cellViews: ->(header) do
26
+ column_indexes.each do |i|
27
+ header.label text: "Heading#{i}"
28
+ end
29
+ end
30
+
31
+ render "#{@path_prefix}/tables/autoload_section", page: page, page_index: page_index, column_indexes: column_indexes
32
+ end, onScrollToBottom: ->(action) do
33
+ action.snackbars_alert message: 'Scrolled to Bottom'
34
+ end, onScrollToTop: ->(action) do
35
+ action.snackbars_alert message: 'Scrolled to Top'
36
+ end
37
+ end
38
+
39
+ end
@@ -17,6 +17,9 @@ json_ui_page json do |page|
17
17
  template.thumbnail title: 'Autoload All', onClick: ->(action) do
18
18
  action.windows_open url: json_ui_garage_url(path: 'tables/autoload_all')
19
19
  end
20
+ template.thumbnail title: 'Autoload as Needed', onClick: ->(action) do
21
+ action.windows_open url: json_ui_garage_url(path: 'tables/autoload_as_needed')
22
+ end
20
23
  end
21
24
 
22
25
  end
@@ -14,4 +14,4 @@ if page_index < 3
14
14
  json.points (from.month.ago.to_date..to.month.ago.to_date).map { |d| { x: d, y: 100 + rand(40) } }
15
15
  end
16
16
  ]
17
- end
17
+ end
@@ -1,34 +1,30 @@
1
-
2
- json.events do
3
-
4
- json.child! do
5
- json.start '2018-12-14'
6
- json.end '2018-12-17'
7
- json.text 'Hackathon'
8
- json.onClick do
9
- json.action 'dialogs/alert-v1'
10
- json.message 'At Town Hall'
1
+ section = json_ui_section json
2
+ section.rows builder: ->(row) do
3
+ row.custom title: 'Hackathon',
4
+ extra: {
5
+ start: '2018-12-14',
6
+ end: '2018-12-17'
7
+ },
8
+ onClick: ->(action) do
9
+ action.dialogs_alert message: 'At Town Hall'
11
10
  end
12
- end
13
11
 
14
- json.child! do
15
- json.start '2018-12-30'
16
- json.end '2018-12-30'
17
- json.text 'Birthday'
18
- json.onClick do
19
- json.action 'dialogs/alert-v1'
20
- json.message 'At home'
12
+ row.custom title: 'Birthday',
13
+ extra: {
14
+ start: '2018-12-30',
15
+ end: '2018-12-30'
16
+ },
17
+ onClick: ->(action) do
18
+ action.dialogs_alert message: 'At home'
21
19
  end
22
- end
23
20
 
24
- json.child! do
25
- json.start '2018-12-31'
26
- json.end '2018-12-31'
27
- json.text 'Conference'
28
- json.onClick do
29
- json.action 'dialogs/alert-v1'
30
- json.message 'In Perth'
21
+ row.custom title: 'Conference',
22
+ extra: {
23
+ start: '2018-12-31',
24
+ end: '2019-01-02'
25
+ },
26
+ onClick: ->(action) do
27
+ action.dialogs_alert message: 'In Perth'
31
28
  end
32
- end
33
29
 
34
30
  end
@@ -5,3 +5,4 @@ require "glib/json_crawler"
5
5
 
6
6
  require 'glib/dynamic_text'
7
7
  require 'glib/crypt'
8
+ require 'glib/test_helpers'
@@ -7,3 +7,4 @@ require_relative './json_crawler/action_crawlers/nav_initiate'
7
7
  require_relative './json_crawler/action_crawlers/windows_open'
8
8
  require_relative './json_crawler/action_crawlers/action_http'
9
9
  require_relative './json_crawler/action_crawlers/forms_submit'
10
+ require_relative './json_crawler/action_crawlers/menu'
@@ -0,0 +1,12 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class Menu < ActionCrawler
4
+ def initialize(http, args, action)
5
+ super(http)
6
+
7
+ @http.router.log action, nil
8
+ crawl args['buttons']
9
+ end
10
+ end
11
+ end
12
+ end
@@ -5,7 +5,7 @@ module Glib
5
5
  super(http)
6
6
 
7
7
  @http = http
8
- if (json = @http.get args['url'], action) && (left_drawer = json['leftDrawer'])
8
+ if (json = (@http.get args['url'], action, args.except('url'))) && (left_drawer = json['leftDrawer'])
9
9
  crawl left_drawer['header']&.[]('childViews')
10
10
  crawl left_drawer['rows']
11
11
  end
@@ -4,7 +4,7 @@ module Glib
4
4
  def initialize(http, args, action)
5
5
  @http = http
6
6
  if (url = args['url'])
7
- json = @http.get url, action
7
+ json = @http.get(url, action, args.except('url'))
8
8
 
9
9
  unless json.nil?
10
10
  crawl json['header']&.[]('childViews')
@@ -12,11 +12,16 @@ module Glib
12
12
  crawl json['footer']&.[]('childViews')
13
13
 
14
14
  json['rightNavButtons']&.each do |button|
15
- click button
15
+ if button['buttons'].present?
16
+ button['buttons'].each do |inner_button|
17
+ click inner_button
18
+ end
19
+ else
20
+ click button
21
+ end
16
22
  end
17
23
  end
18
24
  end
19
-
20
25
  end
21
26
  end
22
27
  end
@@ -8,8 +8,8 @@ module Glib
8
8
  VALID_RESPONSE_CODES = [
9
9
  (200..299).to_a,
10
10
  ## Note, the JSON API does not allow redirects
11
- 401, ## UNAUTHORIZED Should be used for not-logged-in
12
- 403, ## FORBIDDEN Should be used for logged-in but not allowed to access
11
+ # 401, ## UNAUTHORIZED Should be used for not-logged-in
12
+ # 403, ## FORBIDDEN Should be used for logged-in but not allowed to access
13
13
  ].flatten
14
14
 
15
15
  def initialize(context, user, router)
@@ -20,8 +20,8 @@ module Glib
20
20
  @router = router
21
21
  end
22
22
 
23
- def get(url, action, inspect_result = true)
24
- fetch(:get, url, action, {}, inspect_result)
23
+ def get(url, action, params = {}, inspect_result = true)
24
+ fetch(:get, url, action, params, inspect_result)
25
25
  end
26
26
 
27
27
  def post(url, action, params)
@@ -40,14 +40,6 @@ module Glib
40
40
  fetch(:delete, url, action, {})
41
41
  end
42
42
 
43
- def controller
44
- @context.integration_session.controller
45
- end
46
-
47
- def action_name
48
- controller.action_name.to_sym
49
- end
50
-
51
43
  private
52
44
  Response = Struct.new :code, :headers, :media_type, :body do
53
45
  def initialize(*)
@@ -66,13 +58,16 @@ module Glib
66
58
  history << url
67
59
  end
68
60
 
69
- @context.assert_match(URI_REGEXP, url)
61
+ if !URI_REGEXP.match(url)
62
+ raise "Invalid URL: `#{url}`. Make sure to use the absolute URL."
63
+ end
70
64
 
71
65
  http_header = {
72
66
  'Client-DeviceOS' => user[:device],
73
67
  'Client-Version' => user[:version],
74
68
  'X-CSRF-Token' => user[:token]
75
69
  }
70
+ http_header.merge!(params[:headers]) if params[:headers].present?
76
71
 
77
72
  params.each do |name, value|
78
73
  params[name] = '' if value.is_a?(Array) && value.size == 0
@@ -83,6 +78,10 @@ module Glib
83
78
  @context.send(method, url, params: params, headers: http_header)
84
79
  raw_response = @context.response
85
80
  response = Response.new(raw_response.code.to_i, raw_response.headers, raw_response.media_type, raw_response.body)
81
+
82
+ if (controller = @context.controller)
83
+ Glib::JsonCrawler::Coverage.coverage_files.add(controller.class.instance_method(controller.action_name).source_location.first)
84
+ end
86
85
  rescue => ex
87
86
  if !inspect_result
88
87
  case ex
@@ -103,9 +102,10 @@ module Glib
103
102
  if (code = response.code) == 302
104
103
  redirect_uri = URI(response.headers['Location'])
105
104
  redirect_uri.query = [redirect_uri.query, 'format=json'].compact.join('&')
106
- get redirect_uri.to_s, action
105
+ get redirect_uri.to_s, action, params
107
106
  else
108
107
  response_times << response.headers['X-Runtime'].to_f
108
+
109
109
  @context.assert_includes VALID_RESPONSE_CODES, code, "Expected a valid response but was [#{response.code}] #{Rack::Utils::HTTP_STATUS_CODES[response.code.to_i]}:\n#{url}"
110
110
  if response.media_type == 'application/json'
111
111
  JSON.parse(response.body)
@@ -19,10 +19,6 @@ module Glib
19
19
  end
20
20
 
21
21
  def step(http, args)
22
- if (controller = http.controller)
23
- Glib::JsonCrawler::Coverage.coverage_files.add(controller.class.instance_method(http.action_name).source_location.first)
24
- end
25
-
26
22
  case args['view']
27
23
  when 'fields/submit-v1', 'fields/submit'
28
24
  @depth += 1
@@ -40,7 +36,6 @@ module Glib
40
36
 
41
37
  if action.present?
42
38
  @depth += 1
43
- # child =
44
39
  case action
45
40
  when 'initiate_navigation'
46
41
  @read_only_actions.add([action, params['url']])
@@ -48,6 +43,8 @@ module Glib
48
43
  when 'windows/open-v1', 'dialogs/open-v1', 'windows/reload-v1', 'windows/open', 'dialogs/open', 'windows/reload'
49
44
  @read_only_actions.add([action, params['url']])
50
45
  JsonCrawler::WindowsOpen.new(http, params, action)
46
+ when 'sheets/select-v1', 'sheets/select'
47
+ JsonCrawler::Menu.new(http, params, action)
51
48
  when 'http/post-v1', 'http/post'
52
49
  JsonCrawler::ActionHttp.new(:post, http, params, action)
53
50
  when 'forms/submit-v1', 'forms/submit'
@@ -73,7 +70,7 @@ module Glib
73
70
  @depth += 1
74
71
  target_router.read_only_actions.each do |crawler_action|
75
72
  action, url = crawler_action
76
- http.get url, action, false
73
+ http.get(url, action, {}, false)
77
74
  end
78
75
  end
79
76
 
@@ -0,0 +1,40 @@
1
+ module Glib
2
+ module TestHelpers
3
+ def response_assert_equal
4
+ expected = __get_previous_result_from_git
5
+ result = __log(response.body)
6
+ assert_equal JSON.parse(expected), JSON.parse(result), "Result mismatch! #{__git_is_available? ? `git diff #{__log_dir}/#{__log_file}` : ''}"
7
+ end
8
+
9
+ private
10
+ def __git_is_available?
11
+ @__git_is_available ||= (`git status 2>&1` =~ /fatal/).nil?
12
+ end
13
+
14
+ def __log_dir
15
+ if @__log_dir.nil?
16
+ @__log_dir = File.expand_path("#{Rails.root}/test/controllers/#{self.class.to_s.underscore}_results", File.dirname(__FILE__))
17
+ unless File.directory?(@__log_dir)
18
+ FileUtils.mkdir_p(@__log_dir)
19
+ end
20
+ end
21
+ @__log_dir
22
+ end
23
+
24
+ def __log_file
25
+ @__log_file ||= "#{self.method_name}.json"
26
+ end
27
+
28
+ def __log json
29
+ File.open("#{File.join(__log_dir, __log_file)}", "w") do |f|
30
+ f << JSON.pretty_generate( JSON.parse(json) )
31
+ end
32
+ json
33
+ end
34
+
35
+ def __get_previous_result_from_git
36
+ `git checkout -- "#{File.join(__log_dir, __log_file)}" > /dev/null 2>&1` if __git_is_available?
37
+ File.exists?(File.join(__log_dir, __log_file)) ? File.open(File.join(__log_dir, __log_file)).read : "\{\}"
38
+ end
39
+ end
40
+ end
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: 0.5.0
4
+ version: 0.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
@@ -73,6 +73,7 @@ files:
73
73
  - app/controllers/concerns/glib/json/ui.rb
74
74
  - app/controllers/concerns/glib/json/validation.rb
75
75
  - app/controllers/glib/home_controller.rb
76
+ - app/helpers/glib/app_feature_support_helper.rb
76
77
  - app/helpers/glib/dynamic_images_helper.rb
77
78
  - app/helpers/glib/dynamic_texts_helper.rb
78
79
  - app/helpers/glib/forms_helper.rb
@@ -114,6 +115,7 @@ files:
114
115
  - app/views/json_ui/garage/actions/_snackbars.json.jbuilder
115
116
  - app/views/json_ui/garage/actions/_timeouts.json.jbuilder
116
117
  - app/views/json_ui/garage/actions/_windows.json.jbuilder
118
+ - app/views/json_ui/garage/actions/dialogs_oauth_post.json.jbuilder
117
119
  - app/views/json_ui/garage/actions/index.json.jbuilder
118
120
  - app/views/json_ui/garage/forms/_alert_post_data.json.jbuilder
119
121
  - app/views/json_ui/garage/forms/basic.json.jbuilder
@@ -172,6 +174,7 @@ files:
172
174
  - app/views/json_ui/garage/services/index.json.jbuilder
173
175
  - app/views/json_ui/garage/tables/_autoload_section.json.jbuilder
174
176
  - app/views/json_ui/garage/tables/autoload_all.json.jbuilder
177
+ - app/views/json_ui/garage/tables/autoload_as_needed.json.jbuilder
175
178
  - app/views/json_ui/garage/tables/export_import.json.jbuilder
176
179
  - app/views/json_ui/garage/tables/horizontal_scroll.json.jbuilder
177
180
  - app/views/json_ui/garage/tables/index.json.jbuilder
@@ -207,11 +210,13 @@ files:
207
210
  - lib/glib/json_crawler/action_crawler.rb
208
211
  - lib/glib/json_crawler/action_crawlers/action_http.rb
209
212
  - lib/glib/json_crawler/action_crawlers/forms_submit.rb
213
+ - lib/glib/json_crawler/action_crawlers/menu.rb
210
214
  - lib/glib/json_crawler/action_crawlers/nav_initiate.rb
211
215
  - lib/glib/json_crawler/action_crawlers/windows_open.rb
212
216
  - lib/glib/json_crawler/coverage.rb
213
217
  - lib/glib/json_crawler/http.rb
214
218
  - lib/glib/json_crawler/router.rb
219
+ - lib/glib/test_helpers.rb
215
220
  - lib/glib/value.rb
216
221
  - lib/glib/version.rb
217
222
  - lib/tasks/db.rake