glib-web 3.12.0 → 3.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df6b1ad5defcb6d77fa2cff5f8daef5615ca3ce0965efeb7263a8d42e9e9ebe6
4
- data.tar.gz: 8bb3862f75b2d32c3284efc9de83afaa051c4e915a3ed5c1fe1b28b78e5fc0dd
3
+ metadata.gz: 33411954512fada9329818d4e011f5cb70f9c528a034fd87b8737318af18e07d
4
+ data.tar.gz: 492020f2693abdd8ffc38334c771cbe550952044f3030f9221fe163c5c49b103
5
5
  SHA512:
6
- metadata.gz: daa8778895e12cfb01ef928b27a61bc4b8cfbe20eb9c61a7e242a2ae63c8d8690cd45d348335832f79ff2cc3906b7f4c6c4bdfcc415f9db0ee297beb1ee29b6d
7
- data.tar.gz: c002c3203aedaff266113d6dc1ba50320010df33d53f82489cbe21fc207eb2069dc1fa82ed8934dfeccb2bc7c6c611788fbc3dadaa21769ff59039a984df90b4
6
+ metadata.gz: 97d3edb87b4e25bb71318dea8dd8243a2f98be27f74ac612e135100bfb5b12317c2b39e763f4e1301c2e3c08736fa7411f91a5a37eea96e1148b0d9d0e1e9841
7
+ data.tar.gz: 032b11ef90b8b22768459248da39de1a16f6342940cd902974bc96dc7d5a7c11acd7797d599e14bf21b11979b4ed237c053f9d82855856f29a7453b4f6ae98c4
@@ -0,0 +1,28 @@
1
+ module Glib
2
+ module Channel
3
+ class AppearanceChannel < ApplicationCable::Channel
4
+ def subscribed
5
+ stream_for "appearance_#{params[:room]}"
6
+ end
7
+
8
+ def status(data)
9
+ action = {
10
+ action: 'labels/set',
11
+ targetId: 'label-1',
12
+ text: data['text']
13
+ # onSet: {
14
+ # action: 'timeouts/set',
15
+ # interval: 1000,
16
+ # onTimeout: {
17
+ # action: 'labels/set',
18
+ # targetId: 'label-1',
19
+ # text: "Room ##{data['room'].upcase}"
20
+ # }
21
+ # }
22
+ }
23
+
24
+ broadcast_to("appearance_#{data['room']}", action)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ module Glib
2
+ module Channel
3
+ class ChatChannel < ApplicationCable::Channel
4
+ rescue_from StandardError, with: :report_error
5
+
6
+ def subscribed
7
+ stream_for "chat_#{params[:room]}"
8
+ end
9
+
10
+ private
11
+ def report_error(e)
12
+ # Rollbar.error(e)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -6,6 +6,8 @@ module Glib::Json::Libs
6
6
 
7
7
  helper_method :json_ui_app_bundle_id, :json_ui_app_build_version, :json_ui_app_device_os
8
8
  helper_method :json_ui_app_is_android?, :json_ui_app_is_ios?, :json_ui_app_is_web?
9
+ helper_method :json_ui_redirect_back_or_to
10
+
9
11
  end
10
12
 
11
13
  def json_ui_app_bundle_id
@@ -58,7 +60,7 @@ module Glib::Json::Libs
58
60
  JSON.parse(render_to_string(template, locals: args))
59
61
  end
60
62
 
61
- def glib_ui_redirect_to(url)
63
+ def glib_redirect_to(url)
62
64
  respond_to do |format|
63
65
  format.html do
64
66
  redirect_to url
@@ -75,11 +77,30 @@ module Glib::Json::Libs
75
77
  end
76
78
  end
77
79
 
78
- def glib_json_handle_403
79
- render file: Rails.root.join('public', '404.html'), status: :forbidden
80
+ # The behaviour provided by this convenience method assumes that user is logged in.
81
+ # When accessing a forbidden page, redirects to `user_default_url` because we don't
82
+ # want the user to get confused in the scenario where after logging in,
83
+ # glib_redirect_back_or_to tries to open a page that the user doesn't have access of.
84
+ def glib_handle_403(user_default_url)
85
+ respond_to do |format|
86
+ format.html do
87
+ redirect_to user_default_url
88
+ end
89
+ format.json do
90
+ render json: if glib_json_dialog_mode?
91
+ { onLoad: __glib_error_dialog('Access denied', "Make sure you're logged in with the correct account.") }
92
+ else
93
+ {
94
+ onResponse: {
95
+ action: 'windows/open', url: user_default_url
96
+ }
97
+ }
98
+ end, status: Rails.env.test? ? :forbidden : :ok
99
+ end
100
+ end
80
101
  end
81
102
 
82
- def glib_json_handle_404
103
+ def glib_handle_404
83
104
  raise ActionController::RoutingError.new('Not Found')
84
105
 
85
106
  # if json_ui_activated?
@@ -89,6 +110,69 @@ module Glib::Json::Libs
89
110
  # end
90
111
  end
91
112
 
113
+ REDIRECT_BACK_KEY = :glib_return_to_url
114
+
115
+ def glib_handle_401(sign_in_url)
116
+ if !glib_json_dialog_mode? && request.get?
117
+ session[REDIRECT_BACK_KEY] = url_for(params.to_unsafe_h.merge(format: nil))
118
+ end
119
+
120
+ respond_to do |format|
121
+ format.html do
122
+ redirect_to sign_in_url
123
+ end
124
+ format.json do
125
+ render json: {
126
+ # Handle dialogs_open and windows_open
127
+ glib_json_dialog_mode? ? :onLoad : :onResponse => __glib_error_dialog(
128
+ 'Your session has ended', 'Please refresh the page and re-login.')
129
+ }, status: Rails.env.test? ? :unauthorized : :ok
130
+ end
131
+ end
132
+ end
133
+
134
+ def __delete_redirect_back_url(url)
135
+ redirect_url = session.delete(REDIRECT_BACK_KEY) || url
136
+ end
137
+
138
+ def glib_redirect_back_or_to(url)
139
+ redirect_url = __delete_redirect_back_url(url)
140
+ glib_redirect_to redirect_url
141
+ end
142
+
143
+ def json_ui_redirect_back_or_to(url, json_action)
144
+ redirect_url = __delete_redirect_back_url(url)
145
+ json_action.windows_closeAll onClose: ->(subaction) do
146
+ subaction.windows_open url: redirect_url
147
+ end
148
+ end
149
+
150
+ def glib_json_dialog_mode?
151
+ params[:_dialog].present? # E.g. _dialog=v1
152
+ end
153
+
154
+ def __glib_error_dialog(title, message)
155
+ {
156
+ action: 'dialogs/show',
157
+ # Don't show another dialog, just use the current one since it's a new dialog anyway, which means
158
+ # that it wouldn't contain existing user data.
159
+ updateExisting: glib_json_dialog_mode?,
160
+ title: title,
161
+ body: {
162
+ childViews: [
163
+ {
164
+ "view": "label",
165
+ "text": message
166
+ },
167
+ ],
168
+ "padding": {
169
+ "x": 20,
170
+ "y": 22,
171
+ },
172
+ }
173
+ }
174
+ end
175
+
92
176
  def glib_json_handle_500(exception)
93
177
  if json_ui_activated? && Rails.env.production?
94
178
  Rollbar.error(exception, :use_exception_level_filters => true) if defined?(Rollbar)
@@ -129,7 +213,7 @@ module Glib::Json::Libs
129
213
  after_action :__json_traversal_register_dynamic_text
130
214
  end
131
215
 
132
- def json_libs_skip_json_ui(options)
216
+ def json_libs_skip_json_ui(options = {})
133
217
  prepend_before_action options do
134
218
  params[:_skip_render] = 'true'
135
219
  end
@@ -152,13 +236,25 @@ module Glib::Json::Libs
152
236
  rescue_from ActionController::InvalidAuthenticityToken do |exception|
153
237
  sign_out(:user)
154
238
 
239
+ # respond_to do |format|
240
+ # format.json do
241
+ # render json: {
242
+ # onResponse: {
243
+ # action: 'windows/open-v1',
244
+ # url: url
245
+ # }
246
+ # }
247
+ # end
248
+ # end
249
+
155
250
  respond_to do |format|
251
+ format.html do
252
+ redirect_to sign_in_url
253
+ end
156
254
  format.json do
157
255
  render json: {
158
- onResponse: {
159
- action: 'windows/open-v1',
160
- url: root_url
161
- }
256
+ glib_json_dialog_mode? ? :onLoad : :onResponse => __glib_error_dialog(
257
+ 'Your session has expired', 'Please refresh the page and retry.')
162
258
  }
163
259
  end
164
260
  end
@@ -81,7 +81,7 @@ module Glib::Json::Ui
81
81
 
82
82
  private
83
83
  def __json_ui_vue(hash, options)
84
- renderer_path = options[:renderer_path]
84
+ renderer_path = params[:_skip_custom_render] == 'true' ? 'layouts/json_ui/no_custom' : options[:renderer_path]
85
85
  @__json_ui_orig_page = response.body
86
86
  response.body = render_to_string(
87
87
  template: renderer_path,
@@ -1,5 +1,9 @@
1
1
  module Glib
2
2
  class HomeController < ApplicationController
3
+ prepend_before_action do
4
+ params[:_skip_custom_render] = 'true' if params[:custom_render] != 'true'
5
+ end
6
+
3
7
  if try(:glib_auth_inited?)
4
8
  skip_before_action :glib_load_resource
5
9
  skip_before_action :glib_authorize_resource
@@ -35,6 +39,22 @@ module Glib
35
39
  render path
36
40
  end
37
41
 
42
+ def chat
43
+ chat_params = params[:chat]
44
+
45
+ payload = {
46
+ action: 'lists/append',
47
+ targetId: 'list-1',
48
+ row: {
49
+ template: 'thumbnail', title: chat_params[:user], subtitle: chat_params[:body]
50
+ }
51
+ }
52
+
53
+ Glib::Channel::ChatChannel.broadcast_to("chat_#{chat_params[:room]}", payload)
54
+
55
+ render template: 'json_ui/garage/empty'
56
+ end
57
+
38
58
  def init_orders
39
59
  @order_headings = {}
40
60
  @orders = params[:orders] || []
@@ -31,6 +31,7 @@ class Glib::JsonUi::ActionBuilder
31
31
  string :fullscreen # mobile, always
32
32
  length :width
33
33
  bool :closeOnBlur
34
+ bool :updateExisting
34
35
 
35
36
  # def initialize(json, page)
36
37
  # @json = json
@@ -0,0 +1,8 @@
1
+ class Glib::JsonUi::ActionBuilder
2
+ module Fields
3
+ class Reset < Action
4
+ string :targetId
5
+ action :onReset
6
+ end
7
+ end
8
+ end
@@ -124,6 +124,21 @@ module Glib
124
124
  end
125
125
  end
126
126
 
127
+ module Labels
128
+ class Set < Action
129
+ string :targetId
130
+ string :text
131
+ action :onSet
132
+ end
133
+ end
134
+
135
+ module Lists
136
+ class Append < Action
137
+ string :targetId
138
+ hash :row
139
+ end
140
+ end
141
+
127
142
  # FUTURE
128
143
  module Data
129
144
  class Save < Action
@@ -10,6 +10,15 @@ module Glib
10
10
  )
11
11
  end
12
12
 
13
+ def glib_chat_url(options = {})
14
+ Glib::Web::Engine.routes.url_helpers.chat_url(options.merge(
15
+ protocol: request.protocol,
16
+ host: request.host,
17
+ port: request.port,
18
+ _render: params[:_render], format: params[:format])
19
+ )
20
+ end
21
+
13
22
  def json_ui_garage_current_url(options = {})
14
23
  json_ui_garage_url(options.merge(path: params[:path]))
15
24
  end
@@ -89,6 +98,18 @@ module Glib
89
98
  # @generic_content_builder = GenericBuilders::Content.new(json, self, @view_builder)
90
99
  end
91
100
 
101
+ def actionCable(options = {})
102
+ json.actionCable do
103
+ if (on_error = options[:onError])
104
+ json.onError do
105
+ on_error.call(@action_builder)
106
+ end
107
+ end
108
+
109
+ json.channels options[:channels]
110
+ end
111
+ end
112
+
92
113
  def content_builder(panelNames)
93
114
  # NOTE: Can potentially be cached
94
115
  builder = GenericBuilders::Content.new(json, self, @view_builder)
@@ -263,6 +263,16 @@ class Glib::JsonUi::ViewBuilder
263
263
  hash :infoSpec
264
264
  end
265
265
 
266
+ class MultipleUpload < AbstractField
267
+ hash :accepts
268
+ array :files
269
+ string :directUploadUrl
270
+ string :title
271
+ string :subtitle
272
+ string :uploadTitle
273
+ string :uploadFailedText
274
+ end
275
+
266
276
  # TODO
267
277
  # class MultiImage < Text
268
278
  # # file_rules = { fileType: 'image/*', maxFileSize: 5000 }
@@ -66,6 +66,20 @@ section.rows builder: ->(template) do
66
66
  action.dialogs_open fullscreen: 'mobile', url: json_ui_garage_url(path: 'forms/basic', mode: 'dialog')
67
67
  end
68
68
 
69
+ if !Rails.env.test? # Prevent test failure
70
+ template.thumbnail title: 'dialogs/open (page with error)', onClick: ->(action) do
71
+ action.dialogs_open url: json_ui_garage_url(path: 'forms/non_existent', mode: 'dialog')
72
+ end
73
+ end
74
+
75
+ template.thumbnail title: 'dialogs/open (page with dialogs/close)', onClick: ->(action) do
76
+ action.dialogs_open url: json_ui_garage_url(path: 'forms/dialogs_close', mode: 'dialog')
77
+ end
78
+
79
+ template.thumbnail title: 'dialogs/open (page with dialogs/show with updateExisting)', onClick: ->(action) do
80
+ action.dialogs_open url: json_ui_garage_url(path: 'forms/dialogs_update', mode: 'dialog')
81
+ end
82
+
69
83
  template.thumbnail title: 'dialogs/oauth', onClick: ->(action) do
70
84
  if respond_to?(:user_facebook_omniauth_authorize_url)
71
85
  provider = {
@@ -5,7 +5,10 @@ markdown = '## Emphasis' + "\n" +
5
5
  "\n" +
6
6
  '~~Strikethrough~~' + "\n"
7
7
 
8
- action.send "dialogs_#{dialog_mode}", showClose: true, content: ->(dialog) do
8
+ options = {
9
+ updateExisting: true
10
+ }
11
+ action.send "dialogs_#{dialog_mode}", **options, content: ->(dialog) do
9
12
  dialog.body padding: glib_json_padding_body, childViews: ->(body) do
10
13
  body.markdown text: markdown
11
14
 
@@ -0,0 +1,3 @@
1
+ json_ui_response json do |action|
2
+ # do nothing
3
+ end
@@ -0,0 +1,14 @@
1
+ json.title 'Forms'
2
+
3
+ page = json_ui_page json
4
+ render "#{@path_prefix}/nav_menu", json: json, page: page
5
+
6
+ page.scroll childViews: ->(scroll) do
7
+ scroll.label text: 'This content will be replaced'
8
+ end
9
+
10
+ page.on load: ->(action) do
11
+ action.dialogs_close onClose: ->(subaction) do
12
+ subaction.windows_open url: json_ui_garage_url(path: 'home/blank')
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ json.title 'Forms'
2
+
3
+ page = json_ui_page json
4
+ render "#{@path_prefix}/nav_menu", json: json, page: page
5
+
6
+ page.scroll childViews: ->(scroll) do
7
+ scroll.label text: 'This content will be replaced'
8
+ end
9
+
10
+ page.on load: ->(action) do
11
+ render 'json_ui/garage/actions/dialogs_show', json: json, action: action, dialog_mode: :show
12
+ end
@@ -1,5 +1,4 @@
1
1
  json.title 'Forms'
2
- # json.disableDirtyPrompt true
3
2
 
4
3
  data = params[:user] || {}
5
4
 
@@ -36,5 +36,17 @@ page.form options.merge(childViews: ->(form) do
36
36
  # form.fields_multiImage name: 'user[photos][]', width: 'matchParent', label: 'Avatar', accepts: rules, directUploadUrl: rails_direct_uploads_url,
37
37
  # placeholderView: { type: 'avatar', width: 100, height: 100, url: 'data:image/jpeg;base64,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' }
38
38
 
39
+ form.spacer height: 16
40
+ form.fields_multipleUpload \
41
+ name: 'user[multi][]',
42
+ directUploadUrl: rails_direct_uploads_url,
43
+ title: 'Select file or drag and drop here',
44
+ subtitle: 'JPG, PNG or PDF, file size no more than 10MB',
45
+ uploadTitle: 'File added:',
46
+ uploadFailedText: '(UPLOAD FAILED)',
47
+ files: [
48
+ { name: 'File (Example)', signed_id: ActiveStorage::Attachment.last&.signed_id }
49
+ ]
50
+ form.spacer height: 16
39
51
  form.fields_submit text: 'Submit'
40
52
  end)
@@ -1,114 +1,68 @@
1
- json.title 'ActionCable Real-time Update'
1
+ room = params[:room]
2
2
  page = json_ui_page json
3
3
 
4
- online_channel = 'OnlineChannel'
5
- typing_channel = 'IsTypingChannel'
6
- first_user = User.first
7
- second_user = User.offset(1).first
8
- # Implement a page that shows how ActionCable works in json_ui
4
+ random_key = SecureRandom.hex(3)
5
+ user = "randomuser##{random_key}"
9
6
 
10
- # 1. Example for list
11
- # column.panels_list actionCable: socket_config, width: 'matchParent', firstSection: ->(section) do
12
- # section.rows objects: @messages, builder: -> (row, message, index) do
13
- # render 'conversations/message', row: row, message: message, user: current_user
14
- # end
15
- # end
7
+ json.title "User: #{user}"
16
8
 
17
- # page.form url: json_ui_garage_url(path: 'forms/basic_post'), method: 'post', padding: glib_json_padding_body, childViews: ->(form) do
18
- # form.fields_textarea \
19
- # width: 'matchParent',
20
- # label: 'Message',
21
- # onKeyUp: ->(action) do
22
- # action.cables_push channel: 'isTypingChannel', data: { conversationId: 1, userId: 1 }
23
- # end
24
- # end
25
-
26
-
27
- # 3. Example for online status
28
-
29
- # put on app/channels/online_channel.rb
30
- # class OnlineChannel < Glib::Channel::OnlineChannel
31
- # self.channel_name = 'OnlineChannel'
32
- # end
33
-
34
- page.on load: ->(action) do
35
- action.timeouts_set interval: 1000, repeat: true, onTimeout: ->(subaction) do
36
- subaction.cables_push channel: online_channel, event: 'online_status', payload: { status: true, user_id: first_user.id }
37
- end
9
+ if room.present?
10
+ page.actionCable \
11
+ channels: [
12
+ {
13
+ name: 'Glib::Channel::AppearanceChannel',
14
+ options: { targetId: 'label-1', room: room }
15
+ },
16
+ {
17
+ name: 'Glib::Channel::ChatChannel',
18
+ options: { targetId: 'list-1', room: room }
19
+ }
20
+ ],
21
+ onError: ->(action) do
22
+ action.labels_set targetId: 'label-1', text: "Room ##{room.upcase} (OFF)"
23
+ end
38
24
  end
39
25
 
40
- # 4. Example for typing status
41
-
42
- # put on app/channels/is_typing_channel.rb
43
- # class IsTypingChannel < Glib::Channel::IsTypingChannel
44
- # self.channel_name = 'IsTypingChannel'
45
- # end
46
-
47
26
  page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
48
27
 
49
- scroll.panels_split width: 'matchParent', content: ->(content) do
50
- content.left childViews: ->(left) do
51
- online_socket_config = {
52
- channel: online_channel,
53
- filterKey: second_user.id,
54
- params: {
55
- conversation: 2
56
- }
57
- }
58
- left.label actionCable: online_socket_config, text: ' '
59
-
60
- left.fields_textarea \
61
- width: 440,
62
- label: "Messages from #{first_user.full_name}",
63
- onTypeStart: lambda { |action|
64
- action.cables_push \
65
- channel: typing_channel, event: 'typing',
66
- payload: { status: true, user_id: first_user.id }
67
- },
68
- onTypeEnd: lambda { |action|
69
- action.cables_push \
70
- channel: typing_channel,
71
- event: 'typing',
72
- payload: { status: false, user_id: first_user.id }
73
- }
74
- left.spacer height: 10
28
+ if room.present?
29
+ scroll.panels_form url: glib_chat_url, width: 'matchParent', height: 'matchParent', method: 'POST', childViews: ->(form) do
30
+ form.fields_hidden name: 'chat[room]', value: room
31
+ form.fields_hidden name: 'chat[user]', value: user
75
32
 
76
- socket_config = {
77
- channel: typing_channel,
78
- filterKey: first_user.id,
79
- params: {
80
- conversation: 2
81
- }
82
- }
83
- left.label actionCable: socket_config, text: ' '
84
- end
33
+ form.p id: 'label-1', text: "Room ##{room.upcase}"
85
34
 
86
- content.right childViews: ->(right) do
87
- right.label text: ''
88
- right.fields_textarea \
89
- width: 440,
90
- label: "Messages from #{second_user.full_name}",
91
- onTypeStart: lambda { |action|
92
- action.cables_push \
93
- channel: typing_channel, event: 'typing',
94
- payload: { status: true, user_id: second_user.id }
95
- },
96
- onTypeEnd: lambda { |action|
97
- action.cables_push \
98
- channel: typing_channel,
99
- event: 'typing',
100
- payload: { status: false, user_id: second_user.id }
101
- }
102
- right.spacer height: 10
35
+ form.panels_list width: 'matchParent', height: 'matchParent', id: 'list-1', sections: [
36
+ ->(section) do
37
+ section.rows builder: ->(template) do
38
+ template.thumbnail title: 'System', subtitle: 'Feel free to discuss anything here.'
39
+ end
103
40
 
104
- socket_config = {
105
- channel: typing_channel,
106
- filterKey: second_user.id,
107
- params: {
108
- conversation: 2
109
- }
110
- }
111
- right.label actionCable: socket_config, text: ' '
41
+ section.footer childViews: ->(footer) do
42
+ form.fields_text \
43
+ name: 'chat[body]',
44
+ width: 'matchParent',
45
+ onTypeStart: ->(action) do
46
+ action.cables_push \
47
+ event: 'status',
48
+ channel: 'Glib::Channel::AppearanceChannel',
49
+ payload: { text: "#{user} is typing", room: room }
50
+ end,
51
+ onTypeEnd: ->(action) do
52
+ action.cables_push \
53
+ event: 'status',
54
+ channel: 'Glib::Channel::AppearanceChannel',
55
+ payload: { text: "Room ##{room.upcase}", room: room }
56
+ end
57
+ end
58
+ end
59
+ ]
112
60
  end
61
+
62
+ else
63
+ scroll.button text: 'Goto room', onClick: ->(action) { action.windows_open url: json_ui_garage_url(path: 'notifications/action_cable', room: random_key) }
64
+ scroll.spacer height: 8
65
+ scroll.label text: 'Or you can ask other dev for room (by copying the url)'
113
66
  end
67
+
114
68
  end
@@ -0,0 +1,5 @@
1
+ <% content_for :head do %>
2
+ <% end %>
3
+
4
+ <% content_for :header do %>
5
+ <% end %>
@@ -9,8 +9,6 @@
9
9
  <%= csrf_meta_tags %>
10
10
 
11
11
  <%= vite_javascript_tag 'vue_renderer', defer: true %>
12
- <%#= javascript_include_tag 'vue_renderer_extras', defer: true %>
13
-
14
12
  <%= vite_stylesheet_tag 'vue_renderer' %>
15
13
  <%# TODO: Remove this, for dev only %>
16
14
  <%# <script src="https://cdn.tailwindcss.com"></script> %>
data/config/routes.rb CHANGED
@@ -4,5 +4,6 @@ Glib::Web::Engine.routes.draw do
4
4
  post 'json_ui_garage', to: 'home#json_ui_garage'
5
5
  patch 'json_ui_garage', to: 'home#json_ui_garage'
6
6
  delete 'json_ui_garage', to: 'home#json_ui_garage'
7
+ post 'chat', to: 'home#chat'
7
8
  end
8
9
  end
@@ -11,9 +11,9 @@ module Glib
11
11
  crawl left_drawer['body']&.[]('childViews')
12
12
  end
13
13
 
14
- if (on_load = (args.fetch('onLoad', nil)))
15
- perform(on_load)
16
- end
14
+ # if (on_load = (args.fetch('onLoad', nil)))
15
+ # perform(on_load)
16
+ # end
17
17
  end
18
18
  end
19
19
  end
@@ -7,9 +7,8 @@ module Glib
7
7
 
8
8
  VALID_RESPONSE_CODES = [
9
9
  (200..299).to_a,
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
10
+ 401, ## UNAUTHORIZED Should be used for not-logged-in
11
+ 403, ## FORBIDDEN Should be used for logged-in but not allowed to access
13
12
  ].flatten
14
13
 
15
14
  def initialize(context, user, router)
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: 3.12.0
4
+ version: 3.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
@@ -72,6 +72,8 @@ executables: []
72
72
  extensions: []
73
73
  extra_rdoc_files: []
74
74
  files:
75
+ - app/channels/glib/channel/appearance_channel.rb
76
+ - app/channels/glib/channel/chat_channel.rb
75
77
  - app/channels/glib/channel/is_typing_channel.rb
76
78
  - app/channels/glib/channel/online_channel.rb
77
79
  - app/controllers/concerns/glib/analytics/funnel.rb
@@ -95,6 +97,7 @@ files:
95
97
  - app/helpers/glib/json_ui/action_builder/commands.rb
96
98
  - app/helpers/glib/json_ui/action_builder/components.rb
97
99
  - app/helpers/glib/json_ui/action_builder/dialogs.rb
100
+ - app/helpers/glib/json_ui/action_builder/fields.rb
98
101
  - app/helpers/glib/json_ui/action_builder/http.rb
99
102
  - app/helpers/glib/json_ui/action_builder/iap.rb
100
103
  - app/helpers/glib/json_ui/action_builder/panels.rb
@@ -148,6 +151,7 @@ files:
148
151
  - app/views/json_ui/garage/actions/dialogs_oauth_post.json.jbuilder
149
152
  - app/views/json_ui/garage/actions/index.json.jbuilder
150
153
  - app/views/json_ui/garage/actions/partial_update.json.jbuilder
154
+ - app/views/json_ui/garage/empty.json.jbuilder
151
155
  - app/views/json_ui/garage/forms/_alert_post_data.json.jbuilder
152
156
  - app/views/json_ui/garage/forms/_conditional_banner.json.jbuilder
153
157
  - app/views/json_ui/garage/forms/_partial_update_execute.json.jbuilder
@@ -156,6 +160,8 @@ files:
156
160
  - app/views/json_ui/garage/forms/basic_post.json.jbuilder
157
161
  - app/views/json_ui/garage/forms/checkboxes.json.jbuilder
158
162
  - app/views/json_ui/garage/forms/conditional_value.json.jbuilder
163
+ - app/views/json_ui/garage/forms/dialogs_close.json.jbuilder
164
+ - app/views/json_ui/garage/forms/dialogs_update.json.jbuilder
159
165
  - app/views/json_ui/garage/forms/dirty_prompt.json.jbuilder
160
166
  - app/views/json_ui/garage/forms/dynamic_group.json.jbuilder
161
167
  - app/views/json_ui/garage/forms/dynamic_select.json.jbuilder
@@ -269,6 +275,7 @@ files:
269
275
  - app/views/json_ui/garage/views/shareButton.json.jbuilder
270
276
  - app/views/json_ui/garage/views/steppers.json.jbuilder
271
277
  - app/views/json_ui/garage/views/texts.json.jbuilder
278
+ - app/views/layouts/json_ui/no_custom.html.erb
272
279
  - app/views/layouts/json_ui/renderer.html.erb
273
280
  - config/routes.rb
274
281
  - lib/generators/glib/install_generator.rb