glib-web 4.1.4 → 4.2.0

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/glib/glib_direct_uploads_controller.rb +52 -0
  3. data/app/helpers/glib/json_ui/abstract_builder.rb +17 -2
  4. data/app/helpers/glib/json_ui/action_builder/logics.rb +1 -0
  5. data/app/helpers/glib/json_ui/page_helper.rb +10 -1
  6. data/app/helpers/glib/json_ui/view_builder/fields.rb +4 -3
  7. data/app/helpers/glib/json_ui/view_builder/panels.rb +39 -16
  8. data/app/helpers/glib/json_ui/view_builder.rb +1 -1
  9. data/app/models/glib/dummy_job_application.rb +16 -0
  10. data/app/views/json_ui/garage/forms/conditional_value.json.jbuilder +1 -5
  11. data/app/views/json_ui/garage/forms/dialogs_update3.json.jbuilder +1 -1
  12. data/app/views/json_ui/garage/forms/file_upload.json.jbuilder +27 -11
  13. data/app/views/json_ui/garage/forms/new_rich_text.json.jbuilder +4 -4
  14. data/app/views/json_ui/garage/forms/rich_text.json.jbuilder +2 -2
  15. data/app/views/json_ui/garage/forms/show_hide.json.jbuilder +34 -0
  16. data/app/views/json_ui/garage/forms/submit_on_change.json.jbuilder +1 -1
  17. data/app/views/json_ui/garage/forms/text_validation.json.jbuilder +23 -29
  18. data/app/views/json_ui/garage/pages/paste_file.jbuilder +1 -1
  19. data/app/views/json_ui/garage/panels/flow.json.jbuilder +13 -0
  20. data/app/views/json_ui/garage/panels/horizontal.json.jbuilder +13 -0
  21. data/app/views/json_ui/garage/panels/responsive.json.jbuilder +12 -0
  22. data/app/views/json_ui/garage/panels/ul.json.jbuilder +13 -0
  23. data/app/views/json_ui/garage/panels/vertical.json.jbuilder +13 -0
  24. data/app/views/json_ui/garage/views/icon_names.json.jbuilder +1 -1
  25. data/app/views/json_ui/garage/views/treeView.json.jbuilder +1 -1
  26. data/config/routes.rb +2 -0
  27. data/lib/active_storage/service/glib_s3_service.rb +22 -0
  28. data/lib/glib/engine.rb +0 -7
  29. metadata +26 -12
  30. data/lib/glib/blob.rb +0 -23
  31. data/lib/glib/direct_uploads_controller.rb +0 -32
  32. data/lib/glib/s3_service.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d36f47f5f0236550243e1344d2bdee89559141b549575142afbd1ea5a13464d1
4
- data.tar.gz: c772a7b58eb06904c442d220a7eae112eaeb5416774a8db28623caa770ec95e5
3
+ metadata.gz: faf0d291c51c0fa43711bc1e563a85693087ac7979784ef50144838227b36f51
4
+ data.tar.gz: 99cb79b91991380f89387958d6f7378a5e9dd18db2517b3ee24888369e09d01a
5
5
  SHA512:
6
- metadata.gz: 176d31f10a75945b693d0e0f26497d19a95ee63863d9cf585004cfe4b9011c64d5908ee622b3a0a83dd01b3a7d4c8babee9cd84af5c2ec3315aaac8e860dc536
7
- data.tar.gz: e75efdc5c2b79a11c380d3905cb2d8d495c74cb01c88264dc0b362c0393007037d3bb814af0bb70ec0c82ce6779db51ca9ecd2be2f7ebb79a2880636645508ae
6
+ metadata.gz: 0cc7697604c728d1999a4da910991c75e6a9750e9492e8c4489971c60e91f0b8233276a9b6b806737229e7b7950bf14609b89d04845d8b5ef0c6f25d966dd19e
7
+ data.tar.gz: 925654476843e66088de357fe3c6f94b5f16411a8e6e70552dcb0c0199198dd607d519c117d079543d8678c86731f11beb9b28c5760548760d3a162445ad0a85
@@ -0,0 +1,52 @@
1
+ module Glib
2
+ class GlibDirectUploadsController < ::ActiveStorage::DirectUploadsController
3
+ before_action :authenticate_user!
4
+
5
+ rescue_from StandardError do |e|
6
+ if !Rails.env.production?
7
+ raise e
8
+ end
9
+ render json: { message: 'Upload failed' }, status: 500
10
+ end
11
+
12
+ rescue_from Glib::Auth::Policy::UnauthorizedError do
13
+ render json: { message: 'Forbidden' }, status: 403
14
+ end
15
+
16
+ rescue_from ActionController::InvalidAuthenticityToken do
17
+ render json: { message: 'Session expired. Please refresh page' }, status: 401
18
+ end
19
+
20
+ def create
21
+ blob = ActiveStorage::Blob.new # generate blob key
22
+ if blob_args[:prefix].present?
23
+ blob.key = "#{blob_args[:prefix]}/#{blob.key}"
24
+ end
25
+ blob.assign_attributes(**blob_args.except(:tagging, :prefix))
26
+ blob.save!
27
+
28
+ if blob.service.instance_of?(::ActiveStorage::Service::GlibS3Service)
29
+ blob.service.tagging = blob_args[:tagging]
30
+ end
31
+
32
+ render json: direct_upload_json(blob)
33
+ end
34
+
35
+ private
36
+ def blob_args
37
+ params.require(:blob).permit(:filename, :byte_size, :checksum, :content_type, :prefix, :tagging, metadata: {}).to_h.symbolize_keys
38
+ end
39
+
40
+ def direct_upload_json(blob)
41
+ url, headers = blob.service_url_for_direct_upload
42
+ blob.as_json(root: false, methods: :signed_id).merge(direct_upload: {
43
+ url: url,
44
+ headers: headers.merge(blob.service_headers_for_direct_upload)
45
+ })
46
+ end
47
+
48
+ def raise_error
49
+ raise Glib::Auth::Policy::UnauthorizedError
50
+ end
51
+ end
52
+ end
@@ -279,8 +279,23 @@ module Glib
279
279
  end
280
280
  end
281
281
 
282
- def self.hash(propName)
282
+ def self.hash(propName, **options)
283
283
  define_method(propName) do |value|
284
+ value = ActiveSupport::HashWithIndifferentAccess.new(value)
285
+
286
+ required = options[:required] || []
287
+ optional = options[:optional] || []
288
+
289
+ required.each do |req|
290
+ raise ArgumentError, "Hash property: '#{req}' is requred" if value[req.to_s].blank?
291
+ end
292
+
293
+ if optional.present?
294
+ value.except(*required).each do |k, v|
295
+ raise ArgumentError, "Unknown hash property: '#{k}'" if !optional.include?(k.to_sym)
296
+ end
297
+ end
298
+
284
299
  json.set! propName, value
285
300
  end
286
301
  end
@@ -326,7 +341,7 @@ module Glib
326
341
 
327
342
  if value
328
343
  if !Rails.env.production?
329
- if !value.match /^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i
344
+ if !value.match(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i)
330
345
  raise "Invalid color: #{value}"
331
346
  end
332
347
  end
@@ -2,6 +2,7 @@ class Glib::JsonUi::ActionBuilder
2
2
  module Logics
3
3
  class Set < Action
4
4
  string :targetId
5
+ array :targetIds
5
6
  hash :conditionalData
6
7
  hash :data
7
8
  hash :variables
@@ -19,6 +19,15 @@ module Glib
19
19
  )
20
20
  end
21
21
 
22
+ def glib_direct_uploads_url(options = {})
23
+ Glib::Web::Engine.routes.url_helpers.glib_direct_uploads_url(options.merge(
24
+ protocol: request.protocol,
25
+ host: request.host,
26
+ port: request.port,
27
+ _render: params[:_render], format: params[:format])
28
+ )
29
+ end
30
+
22
31
  def json_ui_garage_current_url(options = {})
23
32
  json_ui_garage_url(options.merge(path: params[:path]))
24
33
  end
@@ -237,7 +246,7 @@ module Glib
237
246
  def form(options = {})
238
247
  form = Glib::JsonUi::ViewBuilder::Panels::Form.new(json, self)
239
248
  form.childViews(->(view_builder) { })
240
- panel_options = options.slice!(:url, :method, :local, :onSubmit, :paramNameForFormData, :model, :onChange, :onChangeAndLoad)
249
+ panel_options = options.slice!(:url, :method, :local, :onSubmit, :paramNameForFormData, :model, :onChange, :onChangeAndLoad, :autoValidate)
241
250
 
242
251
  json.fullPageForm do
243
252
  json.view 'panels/fullPageForm'
@@ -66,7 +66,7 @@ class Glib::JsonUi::ViewBuilder
66
66
  @label ||= context.field_label(@prop, @label_args || {})
67
67
  @hint ||= context.hint_label(@prop, @hint_args || {})
68
68
  @placeholder ||= context.placeholder_label(@prop, @placeholder_args || {})
69
- @validation ||= context.field_validation(@prop)
69
+ @validation ||= context.field_validation(@prop) if form._autoValidate || @autoValidate
70
70
 
71
71
  if form.current_dynamic_group.nil?
72
72
  # This is not relevant inside a dynamic group
@@ -83,7 +83,7 @@ class Glib::JsonUi::ViewBuilder
83
83
  # - Placeholder competes with label for space
84
84
  json.placeholder @placeholder if @placeholder
85
85
 
86
- json.validation @validation if @autoValidate
86
+ json.validation @validation if @validation.present?
87
87
  end
88
88
 
89
89
  # To be overridden
@@ -219,7 +219,7 @@ class Glib::JsonUi::ViewBuilder
219
219
 
220
220
  string :titlePrefix
221
221
  panels_builder :content, :template
222
- hash :groupFieldProperties
222
+ array :groupFieldProperties
223
223
 
224
224
  # NOTE: Consider using sub-panel instead (e.g. groupTemplate)
225
225
  # views :groupTemplateViews
@@ -326,6 +326,7 @@ class Glib::JsonUi::ViewBuilder
326
326
  string :storagePrefix
327
327
  hash :metadata
328
328
  string :tagging
329
+ hash :tags
329
330
 
330
331
  required :accepts, :directUploadUrl
331
332
 
@@ -1,7 +1,10 @@
1
+ require 'js_regex'
2
+
1
3
  class Glib::JsonUi::ViewBuilder
2
4
  module Panels
3
5
  class Form < View
4
6
  attr_reader :model_name # See Panels::Form.field_name
7
+ attr_reader :_autoValidate
5
8
  attr_accessor :current_dynamic_group
6
9
 
7
10
  action :onSubmit
@@ -10,6 +13,10 @@ class Glib::JsonUi::ViewBuilder
10
13
  string :paramNameForFormData
11
14
  bool :local
12
15
 
16
+ def autoValidate(autoValidate)
17
+ @_autoValidate = autoValidate
18
+ end
19
+
13
20
  def nested_associations
14
21
  @nested_associations ||= []
15
22
  end
@@ -118,35 +125,51 @@ class Glib::JsonUi::ViewBuilder
118
125
  self.class.field_validation(@model, prop)
119
126
  end
120
127
 
128
+ def self.lookup_error_message(model_name, attribute_name, key)
129
+ message = I18n.t("activerecord.errors.models.#{model_name}.attributes.#{attribute_name}.#{key}", default: nil) if model_name.present? && attribute_name.present?
130
+ message ||= I18n.t("activerecord.errors.models.#{model_name}.#{key}", default: nil) if model_name.present?
131
+ message ||= I18n.t("activerecord.errors.messages.#{key}", default: nil)
132
+ message ||= I18n.t("errors.attributes.#{attribute_name}.#{key}", default: nil) if attribute_name.present?
133
+ message ||= I18n.t("errors.messages.#{key}", default: nil)
134
+ message
135
+ end
136
+
121
137
  def self.field_validation(model, prop)
122
138
  validations = {}
139
+ ignored = ['confirmation', 'comparison', 'uniqueness', 'validates_associated', 'validates_each', 'validates_with']
123
140
  model.class.validators_on(prop).each do |validator|
141
+ next if ignored.include?(validator.kind.to_s)
142
+
124
143
  validations[validator.kind] = validator.options.except(:if, :unless)
125
144
  validations[validator.kind][:message] = validator.options[:message]
126
145
  case validator.kind
146
+ when :absence
147
+ validations[validator.kind][:message] ||= lookup_error_message(model.to_s.underscore, prop, 'present')
127
148
  when :presence
128
- validations[validator.kind][:message] ||= I18n.t('errors.messages.present')
149
+ validations[validator.kind][:message] ||= lookup_error_message(model.to_s.underscore, prop, 'blank')
129
150
  when :acceptance
130
- validations[validator.kind][:message] ||= I18n.t('errors.messages.accepted')
131
- when :confirmation
132
- # raise NotImplemented
151
+ validations[validator.kind][:message] ||= lookup_error_message(model.to_s.underscore, prop, 'accepted')
152
+ validations[validator.kind][:accept] ||= ['1', true]
133
153
  when :numericality
134
- # raise NotImplemented
135
- when :comparison
136
- comparison = validator.options.first[0]
137
- validations[validator.kind][:message] ||= I18n.t("errors.messages.#{comparison}")
154
+ validations[validator.kind][:message] ||= [
155
+ 'not_a_number', 'not_an_integer', 'greater_than',
156
+ 'greater_than_or_equal_to', 'equal_to', 'less_than',
157
+ 'less_than_or_equal_to', 'other_than', 'in', 'odd', 'even'
158
+ ].inject({}) { |prev, curr| prev.merge(curr => lookup_error_message(model.to_s.underscore, prop, curr)) }
138
159
  when :format
139
- validations[validator.kind][:message] ||= I18n.t('errors.messages.invalid')
160
+ if validations[validator.kind][:with].instance_of?(Regexp)
161
+ validations[validator.kind][:with] = JsRegex.new(validations[validator.kind][:with]).source
162
+ end
163
+ if validations[validator.kind][:without].instance_of?(Regexp)
164
+ validations[validator.kind][:without] = JsRegex.new(validations[validator.kind][:without]).source
165
+ end
166
+ validations[validator.kind][:message] ||= lookup_error_message(model.to_s.underscore, prop, 'invalid')
140
167
  when :inclusion
141
- validations[validator.kind][:message] ||= I18n.t('errors.messages.inclusion')
168
+ validations[validator.kind][:message] ||= lookup_error_message(model.to_s.underscore, prop, 'inclusion')
142
169
  when :exclusion
143
- validations[validator.kind][:message] ||= I18n.t('errors.messages.exclusion')
170
+ validations[validator.kind][:message] ||= lookup_error_message(model.to_s.underscore, prop, 'exclusion')
144
171
  when :length
145
- validations[validator.kind][:message] = {
146
- too_long: I18n.t('errors.messages.too_long'),
147
- wrong_length: I18n.t('errors.messages.wrong_length'),
148
- too_short: I18n.t('errors.messages.too_short')
149
- }
172
+ validations[validator.kind][:message] ||= ['too_long', 'wrong_length', 'too_short'].inject({}) { |prev, curr| prev.merge(curr => lookup_error_message(model.to_s.underscore, prop, curr)) }
150
173
  end
151
174
  end
152
175
 
@@ -320,7 +320,7 @@ module Glib
320
320
  string :directUploadUrl
321
321
  hash :accepts
322
322
  string :selected
323
- hash :items
323
+ array :items
324
324
  hash :dropData
325
325
  string :strategy
326
326
  string :storagePrefix
@@ -0,0 +1,16 @@
1
+ module Glib
2
+ class DummyJobApplication
3
+ include ActiveModel::Validations
4
+ include ActiveModel::AttributeMethods
5
+
6
+ attr_accessor :name, :age, :position, :words, :accept
7
+
8
+ validates :name, :position, presence: true
9
+ validates :accept, acceptance: {}, allow_nil: false
10
+ validates :words, length: { maximum: 100, minimum: 1 }
11
+ validates :age, numericality: { only_integer: true, less_than_or_equal_to: 30, greater_than_or_equal_to: 18 }, allow_blank: true
12
+ validates :name, format: { with: /Doe\z/, message: 'This job is for person end with Doe' }
13
+ validates :position, inclusion: { in: ['programmer', 'devops', 'designer'] }, allow_blank: true
14
+
15
+ end
16
+ end
@@ -30,11 +30,7 @@ page.form \
30
30
  form.h2 text: 'Check/uncheck All'
31
31
  form.spacer height: 6
32
32
  form.fields_check name: 'user[check_all]', label: 'All', checkValue: true, onChangeAndLoad: ->(action) do
33
- action.runMultiple childActions: ->(saction) do
34
- saction.logics_set targetId: 'check1', conditionalData: { value: { "==": [{ "var": 'user[check_all]' }, true] } }
35
- saction.logics_set targetId: 'check2', conditionalData: { value: { "==": [{ "var": 'user[check_all]' }, true] } }
36
- saction.logics_set targetId: 'check3', conditionalData: { value: { "==": [{ "var": 'user[check_all]' }, true] } }
37
- end
33
+ action.logics_set targetIds: ['check1', 'check2', 'check3'], conditionalData: { value: { "==": [{ "var": 'user[check_all]' }, true] } }
38
34
  end
39
35
  form.fields_check id: 'check1', name: 'user[check1]', label: 'Check 1', checkValue: true
40
36
  form.fields_check id: 'check2', name: 'user[check2]', label: 'Check 2', checkValue: true
@@ -4,7 +4,7 @@ page = json_ui_page json
4
4
  render "#{@path_prefix}/nav_menu", json: json, page: page
5
5
 
6
6
  page.filePaster \
7
- directUploadUrl: rails_direct_uploads_url,
7
+ directUploadUrl: glib_direct_uploads_url,
8
8
  accepts: {
9
9
  fileType: 'image',
10
10
  maxFileSize: 100,
@@ -11,29 +11,29 @@ render "#{@path_prefix}/nav_menu", json: json, page: page
11
11
 
12
12
  page.form options.merge(childViews: ->(form) do
13
13
  rules = { fileType: 'image', maxFileSize: 5000 }
14
- form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Landscape Photo', accepts: rules, directUploadUrl: rails_direct_uploads_url,
14
+ form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Landscape Photo', accepts: rules, directUploadUrl: glib_direct_uploads_url,
15
15
  value: 'eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBFQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--193dc0d939b9558fc4973fafbba91d989cbb04d4',
16
16
  fileUrl: 'https://imageserver-demo.herokuapp.com/image/itinerarybuilder-demo/o6CKzNt67PWnkPdUEnWMt7pr?h=100&w=100',
17
17
  fileTitle: '1 month ago',
18
18
  placeholderView: { type: 'image', width: 100, height: 75, url: 'https://www.atms.com.au/wp-content/uploads/2019/10/placeholder-1-1024x683.png?x93630' }
19
19
 
20
20
  rules = { fileType: 'image', maxFileSize: 1, fileTypeErrorText: 'Invalid!', maxFileSizeErrorText: 'Too big!' }
21
- form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Avatar', accepts: rules, directUploadUrl: rails_direct_uploads_url,
21
+ form.fields_file name: 'user[photo][]', width: 'matchParent', label: 'Avatar', accepts: rules, directUploadUrl: glib_direct_uploads_url,
22
22
  placeholderView: { type: 'avatar', width: 100, height: 100, url: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxMREBUREhAWFhUWGBcVFRgXFxUVFxcWGRUWFxYVFRUYHSggGB0lHRgVITEhJSkrLi4uGB8zODMtNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOMA3gMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABgcBAwQFAv/EAEAQAAECAwMKAwYEBAYDAAAAAAEAAgMRIQQSMQUGIjJBUWFxgZEHE6FCUnKxwdEUI2LwM4KSskNzg6LC4WOz8f/EABQBAQAAAAAAAAAAAAAAAAAAAAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwC6XuvCQRj7okcUe27UYoxt4TOKDDG3Knkjm3jeGCMdeoeaOcWmQwQZe6/Qc0a+6Lpx+6PbcqOSNbeF44oMMbcqeSOZeN4YIx1+h5oXEG6MEGXuv0HNGuui6cfuvMytl6zWTXi6XuN039hh1koflPxDe4nyILW/qfpO/pFB6oLDhMLTX0XLbLbChmcSNDZ8T2tPqVUNuy/aY38S0PI3A3W/0tkF5qC4bVnZYsPxLT8Ic71AWgZ72ICXmuP+m/7KpUQWzAzzsQP8Y9Ybx9F0szlsb3TFqhjDWJZ6uAVOogvcR2RR+XEa7bouB+S2B0hdOOHCqoVjiDMEg7xQ917FgzqtcHVjucNz9Mf7qjoUFwMFzHahbM3tmPZQfJ3iG10m2mCR+qGZjqw17EqXZNynCtDZwIrXt2gawn7zTUIOt7r1BzRj7ounFHtu1GOCMbeEzigwxtyp5I5t43hgjHXqHmjnXTdGCDL3X6DmjXXRdOP3R7blRyRrZi8cfsgwxtyp5I9t+o5Iw36Hmj3XaDmgMZcqeVEcy8Zj1Rji4yOHZHuLTIYIMvdfoOdUa+6LpxR7btW44b0Y0OEzigwxtyp5URzLxvDD7JDJdR3NRfOnPFlmnBgSfFwJxbD5+87hs27kHt5byzBs7A6M+7ta3F7vhb9cFXeXM9o8abIX5MPc06ZH6n7OQl1UdtdqfFeYkR5c44k4/wDQ4LSgFERAREQEREBERAREQF9wIzmOD2OLXDAtJBHUL4RBOMgZ/OYQ21NvjDzGgB4+Joo7pI81O7PHZHaIsJ7XsO0H0O48FRi78j5Yi2V9+E+XvNNWuG5w+uKC63uv0HOqNfdF04/deLm5nFCtbNDQigacMmstpZ7wXtNaCJnFBhjblTyojmXjeGH2RhvUdz3I5xBujBBl7r9BzqjHXKHnRHi7Vv3Rjb1XY9kBz79BzqjX3KH0R7Q2rce6MaHCbseyDDG3KnlRCy8bw9UYS6jsOyiGfecvkNNlgO/McNNw9hp9kH3j6BBoz2zxul1mszq4RIg2b2sO/edirxEQEREBERAREJQEXZZskx4mpAiO4hpl3NF3Q81LYf8AAI5uYPqg8VF7UTNS1j/AJ5OYfquC05MjQ/4kGI3iWul3wQciIiAiIgIiINlnjuhvD2OLXNMwRQgq0s1M5G2wXHybHaKjY8D2mcd4VUrZZ47ob2vY4tc0zaRiCgvZ7r9BzqjX3RdOPpVeJmtl8WuDeoIzZCI3/m0bj6VXttaCJnH97EGGNuVPKiObfqOVUYb1HfZHuLaNw7oDWXKnlRHMv1HqjCSZOw7I5100Mm4k7BvM0HlZ05ebZbOXgabtGEDtdLWI3DHsqeixC9xc4kucSSTiSaklernXlj8XaHPH8NuhDH6Rt5nHsvHQEREBERARF6WbuSzabQ2H7Os87mjHqcOqDtzczXiWrTcbkL3pVdvDB9fmp7k3INns8rkIXvedpO7nDpJejChhrQ1oAaAAAMABgF9ICIiAiIg8nKeblnjzvQw13vM0XdZUPVQHOHNyJZDenfhkyDwMDsDhsKtRarTZ2xGOhvE2uEiOCClUXblnJ5s8d8I+ydE72mrT2+q4kBERAREQd2RspvssZsZmLcRsc04tPP7K5LFaW2iG2PDM2uAI3jeDxBmFRqmfhxlry4psrzoRKs4RJYfzAdwN6Cx3Ov0HOqNdcoedEeLurj3RgDqux7IDn36Dmoxn/lT8PZfJadOMS2mxntn1A6qUOaBq491UmfWUfPtr5GbYf5bf5dY/1T7BBH0REBERAREQFYfh3YbsB0YisR0h8LafOfZV4VcGQYHl2WC3dDbPmQCfUlB3oiICIiAiIgIiIIX4j2GbYccCoPlu5GrfW93UEVsZ2QA+xRgdjbw5tId9FU6AiIgIiIC+oby0hzTIgggjEEVBC+UQXXkLKYj2dloGLhJwGx4o4dwu5zL9RyUB8MLfpRLM7AjzW8xJrvS72U+eSKNw7oOfKMb8PBiRidRjnDmBQd5Kj3OJMzianmrT8QbW5lhLTjEe1nSrj/bJVWgIiICIiAiIgK3834/mWWC7/wAbQeYF0+oKqBWJ4d2u9Z3wtsN0x8L6/MOQStERAREQEREBERB4+d0e5Yox3tujm4gfVVQp54kWuTIUEe0S88m0HqT2UDQEREBERAREQelm5bvItcGLOQDwHfC7Rd6Eq6L1ynVUKVeOSLQI1nhRTi+Gwmu26J+s0EP8U7RNlnZvMR3a6B/cVXym3ik786CBgIbj3d/0oSgIiICIiAiIgKW+HN/z4khoXJOO4zm35OUSU88NXjy4w9q80nlIgeoKCZoiICIiAiIgIiIK1z/D/wAXNzSG3GhnECcz3J9FGlNfEt4vQBtk8nkS2XyKhSAiIgIiICIiArazFPmWCFXVL29nlVKrP8OHn8CZbIrx/tYfqg8TxRZKPB/yyP8AeVC1O/FKGZ2d53RGnoWEfMqCICIiAiIgIiIC78iZVfZYoiMrsc3Y5u7hzXAiC5cmZQZaITYsMzB7g7WniF1KBeHFuk+JAJ1gHtHFtHS6Ef0qeoCIiAiIgLiyxlRlmhGJE5NAxc7YAu1V14hW6/aGwgaQ21+J1T6BqDwsr5SfaYpivxNABg1owaFxIiAiIgIiICIiArP8M3XbE874zv7If2VYK1/DuEBYGl3tPe6vOX0QcniZDv2VkSWpEAPJzSPmAqzV0Z02QRrFGY2RNwuA4s0h8lS6AiIgIiICIiAiIg6LBa3QYrIrNZhmOO8HgRMdVcFgtbY0NsVh0XCY4bweINFS6n/hvaSYUWGcGOBH8wMx3bPqgmCIiAiIg48rW9tngviuwaKDe40a0cyqgtEd0R7nuM3OJcTxJmpn4k2kzgwtmk88TQDtXuoQgIiICIiAiIgIiICufNixXbFAbgfLDjzdpH5qn7DZjFishDF7mtHUymrxc0iQZgABThRBny7tTUYd1S2X7B+HtMWDsa43fhOk30IV0snPSw4qC+J2TJ+XamCn8N/zYfmOyCAIiICIiAiIgIi3WWyviuDIbC5x2AT77hxQaVaGZmSjZ7PpiT4hvuG4Sk1p4yr1XHm1miIJEWPJ0QVa3FrDv/UfQKVoCIiAiIgjGfeSTGgiIwTdCmSBiWGV6XKQPdVurvUOzlzOvkxbMAHGroeAJ3s3HhhyQQFFsjwXMcWvaWuGIIkR0WtAREQEREBERBK/DfJ/mWvzCKQml38zptb/AMj0Vn37lMdu5R3MfJhgWNplpxT5jt4aRoDtXqVImS9rHjuQYv36YbVz5RsbYsJ9nfqvBE9xOBHEGRXS+Xs48EZKWljxQUZbrI6DFfCeJOYS0/ccCK9VoVjeIWQTEh/imN02CUUe8wYP5t28OSrlARF9wYTnuDWtLnEyAAmSeSD4XRYrDEjOuwobnngKDmcB1UzyFmQAA+0mZx8sGg+Jwx5D1UwgQGw2hrGhrRgGgAdgghOSsxCZOtESX6GVPV+Hbupjk/J8KA27Chho2yxPM4nqulEBERAREQEREBERBxZTyVBtDZRYYduODhycKhQzKuYsRs3QH3x7rpNd0OB9FYCIKWtVlfCddiMcw7nAjtvWlXVarKyK27EY1zdzgD/8UNy5mQKvsx/03H+1x+R7oIOi+osMtcWuBDgZEESIO4hfKAvZzSyP+KtLWEflt04nwj2epp3XjtaSQAJk0AGJJwAVwZpZFbY7PddLzXydE5yo0cB85oPadoV6SwksXL9cNiwyft4cao+fs4cN6DJZcrjsQMv6WCwwEHSw41R4JOjhwogy19+hFNu2YwkQqqz1zbNki32D8l50f0OxuH6cOStV5B1ceFKLTarMyLCdCjCYcJEH0M9h3FBR0GE57gxoJc4gADEk7FaGbGbzbKy8ZOiuGk7d+lvDjtWnIOaX4SO+I43hhBO0NOJduds771IkBERAREQEREBERAREQEREBERAREQeFnPm621MvNAbGA0Xe9+l3DjsVYRoRY4tcCHNJBBxBGIV2Lx7bmpCj2lloiaoGkyX8Rw1Z8N++QQeNmDm7dlbIzf8lp/9h+nfcp5cvaX7osMEtYSGwbByCOBnTV9ONEAOv0w2oX3KY7Vl8jqY8KURhA1seNaIMB9+mG1C+5o4rLyDq48KIwgCTseNUAsuVx2IGXtJYYCNbDjWqOBJm3Dsg+mRL1CFoiwZcv3itzyDq48KUWWOAEjj+5IONF0PgbcDu+y0ESxQYREQEREBERAREQEREBERARfTGE4BdDGNbiaoNbYUhN3QfdbQy9penJYZMGbsONao4EmbcO3OiAHX6YbUL7uj+6rLyDq48KURpAEjj+5VQC25XHYgbfrhsWGAjWw41R4J1cOFKoMllyo5IGX6lYYCDN2HdHgkzbh2QGvv0NNqF93RWXkGjce1EaQBJ2Pf1QC25UV2IGXtL90WGAjWw71RwJM24dudEBrr9DTasRDLRIn819PIOrj2ojSAJOx7+qD4iWbce60uYRiF0MBGth3qskkmYw/exByIustacBPlRa3QW4TIPGvyQaEW91nl7QWPw53hBpRbhZydo7p5FZFwQaUXSYDRiSshu1rRLf8APFBoZDJwC2CEAZEzO4LbEde1T9FgESkdb67KoPqJo1HKWxfIZe0lhgIq7DujgSZtw7eiA11+hptQvu6P7qsvIOrj2ojSAJOx7+qAW3KiuxAy9pfuiwwEa2HeqOBJmMO3OiAHX6Gm1C65QV2rLzPVx7IwgUdj3QfVp1eqWfVREGqy49PskfW7IiDZasOv3WYGr3REGuy49FiPrdkRBstWHX7rMHV7rKINVlx6LEXX7IiDZasBzWYOp3+qyiDVZcTyWIuv2+iIg2WrAc1mHqdD9URB8WXEr5fr9R9ERBttOr1Sz6vdZRBpsuPT7JH1uyIg2WrDqswdTuiINdlxPJYtOt0REH//2Q==' }
23
23
 
24
24
  rules = { fileType: 'pdf', maxFileSize: 5000 }
25
- form.fields_file name: 'user[pdf1][]', width: 'matchParent', label: 'PDF Document', accepts: rules, directUploadUrl: rails_direct_uploads_url,
25
+ form.fields_file name: 'user[pdf1][]', width: 'matchParent', label: 'PDF Document', accepts: rules, directUploadUrl: glib_direct_uploads_url,
26
26
  placeholderView: { type: 'image', width: 100, height: 100, url: 'data:image/webp;base64,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' }
27
27
 
28
28
  rules = { fileType: ['pdf', 'image'], maxFileSize: 5000 }
29
- form.fields_file name: 'user[pdf2][]', width: 'matchParent', label: 'PDF/Image File', accepts: rules, directUploadUrl: rails_direct_uploads_url
29
+ form.fields_file name: 'user[pdf2][]', width: 'matchParent', label: 'PDF/Image File', accepts: rules, directUploadUrl: glib_direct_uploads_url
30
30
 
31
31
  rules = { fileType: 'zip', maxFileSize: 5000 }
32
- form.fields_file name: 'user[zip][]', width: 'matchParent', label: 'ZIP Document', accepts: rules, directUploadUrl: rails_direct_uploads_url
32
+ form.fields_file name: 'user[zip][]', width: 'matchParent', label: 'ZIP Document', accepts: rules, directUploadUrl: glib_direct_uploads_url
33
33
 
34
34
  # TODO
35
35
  # rules = { fileType: 'image/*', maxFileSize: 1, fileTypeErrorText: 'Invalid!', maxFileSizeErrorText: 'Too big!' }
36
- # form.fields_multiImage name: 'user[photos][]', width: 'matchParent', label: 'Avatar', accepts: rules, directUploadUrl: rails_direct_uploads_url,
36
+ # form.fields_multiImage name: 'user[photos][]', width: 'matchParent', label: 'Avatar', accepts: rules, directUploadUrl: glib_direct_uploads_url,
37
37
  # placeholderView: { type: 'avatar', width: 100, height: 100, url: 'data:image/jpeg;base64,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' }
38
38
 
39
39
  form.spacer height: 16
@@ -41,35 +41,51 @@ page.form options.merge(childViews: ->(form) do
41
41
  form.spacer height: 8
42
42
  form.fields_multiUpload \
43
43
  name: 'user[multi][]',
44
+ id: 'upload_1',
44
45
  width: 360,
45
46
  accepts: { fileType: 'image', maxFileSize: 10 },
46
- directUploadUrl: rails_direct_uploads_url,
47
+ directUploadUrl: glib_direct_uploads_url,
47
48
  uploadTitle: 'Files uploaded:',
48
49
  storagePrefix: 'glib',
49
50
  metadata: {
50
51
  foo: 'bar',
51
52
  zoo: 'baz'
52
53
  },
53
- tagging: 'key=value&key1=value1',
54
+ # tagging: 'key=value&key1=value1',
55
+ tags: { key: 'value', key1: 'value1' },
54
56
  files: [
55
- { name: 'File (Example)', signed_id: ActiveStorage::Attachment.last&.signed_id }
57
+ { name: 'File (Example)', signed_id: ActiveStorage::Attachment.first&.signed_id }
56
58
  ]
59
+ form.button text: 'Clear files', onClick: ->(action) do
60
+ action.components_set targetId: 'upload_1', data: { files: [], value: nil }
61
+ end
62
+
57
63
  form.spacer height: 16
58
64
  form.label text: 'File upload with onFinishUpload'
59
65
  form.spacer height: 8
60
66
  form.fields_multiUpload \
61
67
  name: 'user[multi2][]',
68
+ id: 'upload_2',
62
69
  width: 360,
63
70
  accepts: { fileType: 'image', maxFileSize: 5000 },
64
- directUploadUrl: rails_direct_uploads_url,
71
+ directUploadUrl: glib_direct_uploads_url,
65
72
  uploadTitle: 'Files uploaded:',
66
73
  onFinishUpload: ->(action) { action.forms_submit }
74
+ form.button text: 'Populate files', onClick: ->(action) do
75
+ action.components_set targetId: 'upload_2', data: {
76
+ files: [
77
+ { name: 'File (Example)', signed_id: ActiveStorage::Attachment.last&.signed_id }
78
+ ],
79
+ value: [1]
80
+ }
81
+ end
82
+
67
83
  form.spacer height: 16
68
84
  form.label text: 'Sign'
69
85
  form.spacer height: 8
70
86
  form.fields_sign \
71
87
  name: 'user[sign]',
72
- directUploadUrl: rails_direct_uploads_url,
88
+ directUploadUrl: glib_direct_uploads_url,
73
89
  width: 300, height: 150,
74
90
  validation: { required: { message: 'add your signature!' } }
75
91
  form.spacer height: 24
@@ -23,16 +23,16 @@ page.form url: json_ui_garage_url(path: 'forms/basic_post'), method: 'post', pad
23
23
 
24
24
  json.images do
25
25
  json.child! do
26
- json.value "eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBFQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--193dc0d939b9558fc4973fafbba91d989cbb04d4"
26
+ json.value 'eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBFQT09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--193dc0d939b9558fc4973fafbba91d989cbb04d4'
27
27
  # json.fileTitle "hita i hanom hg.jpg"
28
- json.fileUrl "https://imageserver-demo.herokuapp.com/image/itinerarybuilder-demo/o6CKzNt67PWnkPdUEnWMt7pr?h=100&w=100"
28
+ json.fileUrl 'https://imageserver-demo.herokuapp.com/image/itinerarybuilder-demo/o6CKzNt67PWnkPdUEnWMt7pr?h=100&w=100'
29
29
  end
30
30
  end
31
31
 
32
32
  json.imageUploader do
33
33
  json.fieldName 'user[images_attributes]'
34
- json.accepts(fileType: "image/*", maxFileSize: 5000)
35
- json.directUploadUrl rails_direct_uploads_url
34
+ json.accepts(fileType: 'image/*', maxFileSize: 5000)
35
+ json.directUploadUrl glib_direct_uploads_url
36
36
  end
37
37
  end
38
38
 
@@ -47,7 +47,7 @@ page.form url: json_ui_garage_url(path: 'forms/basic_post'), method: 'post', pad
47
47
  imageUploader: {
48
48
  name: 'user[images_attributes][]',
49
49
  accepts: { fileType: 'image/*', maxFileSize: 5000 },
50
- directUploadUrl: rails_direct_uploads_url
50
+ directUploadUrl: glib_direct_uploads_url
51
51
  },
52
52
  onChange: ->(action) do
53
53
  action.forms_submit overrideUrl: json_ui_garage_url(path: 'forms/rich_text_preview')
@@ -72,7 +72,7 @@ page.form url: json_ui_garage_url(path: 'forms/basic_post'), method: 'post', pad
72
72
  # json.imageUploader do
73
73
  # json.name 'user[images_attributes][]'
74
74
  # json.accepts(fileType: 'image/*', maxFileSize: 5000)
75
- # json.directUploadUrl rails_direct_uploads_url
75
+ # json.directUploadUrl glib_direct_uploads_url
76
76
  # end
77
77
  # end
78
78
  end
@@ -342,6 +342,40 @@ page.form \
342
342
  form.fields_text id: 'field4', name: 'user[loadif_target8]', width: 'matchParent', value: params[:key]
343
343
  end
344
344
 
345
+ # form.fields_check name: 'user[loadif7]', label: 'Show target nested panels', checkValue: 'true', uncheckValue: 'false', value: 'false', onChangeAndLoad: ->(action) do
346
+ # action.logics_set targetId: 'panel7a', conditionalData: { displayed: { "==": [{ "var": 'user[loadif7]' }, 'true'] } }
347
+ # end
348
+
349
+ form.spacer height: 20
350
+ options = [
351
+ { text: 'Option 1', value: 'option1' },
352
+ { text: 'Option 2', value: 'option2' }
353
+ ]
354
+ form.fields_select name: 'user[loadif7]', width: 'matchParent', label: 'Select "show"', options: options, value: '', onChangeAndLoad: ->(action) do
355
+ action.runMultiple childActions: ->(saction) do
356
+ saction.logics_set targetId: 'panel7a', conditionalData: { displayed: { "==": [{ "var": 'user[loadif7]' }, 'option1'] } }
357
+ saction.logics_set targetId: 'panel7b', conditionalData: { displayed: { "==": [{ "var": 'user[loadif7]' }, 'option2'] } }
358
+ end
359
+ end
360
+
361
+ form.panels_vertical \
362
+ id: 'panel7a',
363
+ styleClass: 'border-2',
364
+ width: 'matchParent',
365
+ padding: { top: 8, right: 8, bottom: 8, left: 8 },
366
+ childViews: ->(res) do
367
+ res.fields_text name: 'user[loadif_target9]', width: 'matchParent', value: 'Value 7a'
368
+ end
369
+
370
+ form.panels_vertical \
371
+ id: 'panel7b',
372
+ styleClass: 'border-2',
373
+ width: 'matchParent',
374
+ padding: { top: 8, right: 8, bottom: 8, left: 8 },
375
+ childViews: ->(res) do
376
+ res.fields_text name: 'user[loadif_target9]', width: 'matchParent', value: 'Value 7b'
377
+ end
378
+
345
379
  form.spacer height: 20
346
380
  form.fields_submit text: 'Submit'
347
381
 
@@ -113,7 +113,7 @@ page.scroll childViews: ->(scroll) do
113
113
  width: 'matchParent',
114
114
  label: 'Avatar',
115
115
  accepts: rules,
116
- directUploadUrl: rails_direct_uploads_url,
116
+ directUploadUrl: glib_direct_uploads_url,
117
117
  placeholderView: { type: 'avatar', width: 100, height: 100, url: 'data:image/jpeg;base64,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' },
118
118
  onChange: ->(action) do
119
119
  action.sheets_select message: 'Submit data?', buttons: ->(menu) do
@@ -4,15 +4,18 @@ page = json_ui_page json
4
4
  render "#{@path_prefix}/nav_menu", json: json, page: page
5
5
 
6
6
  page.form \
7
+ model: Glib::DummyJobApplication.new,
7
8
  url: json_ui_garage_url(path: 'forms/generic_post'),
8
9
  method: 'post',
9
10
  padding: glib_json_padding_body,
11
+ autoValidate: true,
10
12
  childViews: ->(form) do
11
13
  form.fields_text \
14
+ prop: :name,
12
15
  name: 'user[name]',
13
16
  width: 'matchParent',
14
- label: 'Name',
15
- validation: { required: { message: 'Required' }, format: { regex: 'Doe$', message: 'The name has to end with "Doe"' } }
17
+ label: 'Name'
18
+
16
19
 
17
20
  form.fields_email \
18
21
  name: 'user[email]',
@@ -25,12 +28,11 @@ page.form \
25
28
  label: 'URL'
26
29
 
27
30
  form.fields_number \
28
- name: 'user[number]',
31
+ prop: :age,
32
+ name: 'user[age]',
29
33
  width: 'matchParent',
30
- label: 'Number',
31
- validation: { required: { message: 'Required' } },
32
- leftText: 'USD',
33
- rightText: '.00'
34
+ label: 'Age'
35
+
34
36
 
35
37
  form.fields_phone \
36
38
  name: 'user[phone1]',
@@ -52,32 +54,21 @@ page.form \
52
54
  leftIcon: 'lock'
53
55
 
54
56
  form.fields_textarea \
55
- name: 'user[textarea]',
57
+ prop: :words,
58
+ name: 'user[words]',
56
59
  width: 'matchParent',
57
60
  label: 'Textarea with maxLength',
58
- maxLength: 50,
59
- validation: { required: { message: 'Required' } }
60
-
61
- # options = ['male', 'female'].map { |i| { text: i.humanize, value: i } }
62
- # form.fields_select \
63
- # name: 'user[gender]',
64
- # width: 'matchParent',
65
- # label: 'Gender',
66
- # validation: { required: { message: 'Required' } },
67
- # options: options
68
-
69
- languages = {
70
- 'brisbane' => 'Brisbane',
71
- 'canberra' => 'Canberra',
72
- 'melbourne' => 'Melbourne',
73
- 'sydney' => 'Sydney',
74
- }
61
+ maxLength: 1000
62
+
63
+
64
+ options = ['programmer', 'devops', 'designer', 'ceo', 'office_boy'].map { |v| { text: v.humanize, value: v } }
75
65
  form.fields_select \
76
- name: 'user[city]',
66
+ prop: :position,
67
+ name: 'user[position]',
77
68
  width: 'matchParent',
78
- label: 'City',
79
- options: languages.map { |k, v| { value: k, text: v } },
80
- validation: { required: { message: 'Required' } }
69
+ label: 'Position',
70
+ options: options
71
+
81
72
 
82
73
  form.spacer height: 10
83
74
  form.h4 text: 'Gender'
@@ -104,6 +95,9 @@ page.form \
104
95
  group.fields_check checkValue: 4, label: 'Mobile Development'
105
96
  end
106
97
 
98
+ form.spacer height: 10
99
+ form.fields_check prop: :accept, label: 'Accept terms & condition', name: 'user[accept]'
100
+
107
101
  form.spacer height: 30
108
102
  form.fields_submit text: 'Submit'
109
103
  form.fields_submit text: 'Submit (disable if form invalid)', disableIfFormInvalid: true
@@ -5,7 +5,7 @@ page = json_ui_page json
5
5
  render "#{@path_prefix}/nav_menu", json: json, page: page
6
6
 
7
7
  page.filePaster \
8
- directUploadUrl: rails_direct_uploads_url,
8
+ directUploadUrl: glib_direct_uploads_url,
9
9
  accepts: {
10
10
  fileType: 'image',
11
11
  maxFileSize: 100,
@@ -4,6 +4,19 @@ page = json_ui_page json
4
4
  render "#{@path_prefix}/nav_menu", json: json, page: page
5
5
 
6
6
  page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
7
+ scroll.h1 text: 'Show/hide'
8
+ scroll.panels_flow id: 'flow1', width: 300, innerPadding: { top: 0 }, backgroundColor: '#b3bac2', childViews: ->(panel) do
9
+ panel.button text: '1'
10
+ panel.button text: '2'
11
+ panel.button text: '3'
12
+ end
13
+ scroll.button text: 'show', onClick: ->(action) do
14
+ action.components_set targetId: 'flow1', data: { displayed: true }
15
+ end
16
+ scroll.button text: 'hide', onClick: ->(action) do
17
+ action.components_set targetId: 'flow1', data: { displayed: false }
18
+ end
19
+
7
20
  scroll.h1 text: 'Basic'
8
21
  scroll.panels_flow width: 300, innerPadding: { top: 0 }, backgroundColor: '#b3bac2', childViews: ->(panel) do
9
22
  panel.button text: '1'
@@ -4,6 +4,19 @@ json_ui_page json do |page|
4
4
  render "#{@path_prefix}/nav_menu", json: json, page: page
5
5
 
6
6
  page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
7
+ scroll.h1 text: 'Show/hide'
8
+ scroll.panels_horizontal id: 'hor1', width: 200, height: 100, backgroundColor: '#b3bac2', childViews: ->(panel) do
9
+ panel.button text: '1'
10
+ end
11
+ scroll.button text: 'show', onClick: ->(action) do
12
+ action.components_set targetId: 'hor1', data: { displayed: true }
13
+ end
14
+ scroll.button text: 'hide', onClick: ->(action) do
15
+ action.components_set targetId: 'hor1', data: { displayed: false }
16
+ end
17
+
18
+ scroll.label text: "\n"
19
+
7
20
  scroll.h1 text: 'Basic'
8
21
  scroll.panels_horizontal backgroundColor: '#b3bac2', childViews: ->(panel) do
9
22
  panel.button text: '1'
@@ -4,6 +4,18 @@ page = json_ui_page json
4
4
  render "#{@path_prefix}/nav_menu", json: json, page: page
5
5
 
6
6
  page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
7
+ scroll.h1 text: 'Show/hide'
8
+ scroll.panels_responsive id: 'res1', width: 300, backgroundColor: '#b3bac2', childViews: ->(panel) do
9
+ panel.button text: '1'
10
+ panel.button text: '2'
11
+ end
12
+ scroll.button text: 'show', onClick: ->(action) do
13
+ action.components_set targetId: 'res1', data: { displayed: true }
14
+ end
15
+ scroll.button text: 'hide', onClick: ->(action) do
16
+ action.components_set targetId: 'res1', data: { displayed: false }
17
+ end
18
+
7
19
  scroll.h1 text: 'Panels Columns'
8
20
  scroll.label text: 'Shrink the browser\'s width to see how the column panels are rearranged. On mobile screens, they are always arranged vertically'
9
21
  scroll.spacer height: 8
@@ -4,6 +4,19 @@ page = json_ui_page json
4
4
  render "#{@path_prefix}/nav_menu", json: json, page: page
5
5
 
6
6
  page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
7
+ scroll.h2 text: 'Show/hide'
8
+ scroll.spacer height: 6
9
+ scroll.panels_ul id: 'ul', childViews: ->(li) do
10
+ li.label text: 'text1'
11
+ li.label text: 'text2'
12
+ end
13
+ scroll.button text: 'show', onClick: ->(action) do
14
+ action.components_set targetId: 'ul', data: { displayed: true }
15
+ end
16
+ scroll.button text: 'hide', onClick: ->(action) do
17
+ action.components_set targetId: 'ul', data: { displayed: false }
18
+ end
19
+ scroll.spacer height: 14
7
20
  scroll.h2 text: 'Standard Usage'
8
21
  scroll.spacer height: 6
9
22
  scroll.panels_ul childViews: ->(ul) do
@@ -4,6 +4,19 @@ json_ui_page json do |page|
4
4
  render "#{@path_prefix}/nav_menu", json: json, page: page
5
5
 
6
6
  page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
7
+
8
+ scroll.h1 text: 'Show/Hide'
9
+ scroll.panels_vertical id: 'vert1', width: 200, height: 100, backgroundColor: '#b3bac2', childViews: ->(panel) do
10
+ panel.button text: 'Button1'
11
+ end
12
+ scroll.button text: 'show', onClick: ->(action) do
13
+ action.components_set targetId: 'vert1', data: { displayed: true }
14
+ end
15
+ scroll.button text: 'hide', onClick: ->(action) do
16
+ action.components_set targetId: 'vert1', data: { displayed: false }
17
+ end
18
+
19
+ scroll.label text: "\n"
7
20
  scroll.h1 text: 'Basic'
8
21
  scroll.panels_vertical backgroundColor: '#b3bac2', childViews: ->(panel) do
9
22
  panel.button text: 'Button1'
@@ -2257,7 +2257,7 @@ page.scroll padding: glib_json_padding_body, childViews: ->(scroll) do
2257
2257
  icon_names.each do |icon_name|
2258
2258
  scroll.panels_column lg: { cols: 4 }, childViews: ->(column) do
2259
2259
  column.panels_horizontal align: 'middle', childViews: ->(horizontal) do
2260
- horizontal.icon spec: icon_name
2260
+ horizontal.icon name: icon_name
2261
2261
  horizontal.spacer width: 6
2262
2262
  horizontal.label text: icon_name
2263
2263
 
@@ -11,7 +11,7 @@ json_ui_page json do |page|
11
11
  flow.treeView \
12
12
  inputName: 'user',
13
13
  url: json_ui_garage_url(path: 'forms/generic_post'),
14
- directUploadUrl: rails_direct_uploads_url,
14
+ directUploadUrl: glib_direct_uploads_url,
15
15
  width: 240,
16
16
  selected: 'parent-1',
17
17
  items: [
data/config/routes.rb CHANGED
@@ -5,5 +5,7 @@ Glib::Web::Engine.routes.draw do
5
5
  patch 'json_ui_garage', to: 'home#json_ui_garage'
6
6
  delete 'json_ui_garage', to: 'home#json_ui_garage'
7
7
  post 'chat', to: 'home#chat'
8
+
9
+ resources :glib_direct_uploads, only: [:create]
8
10
  end
9
11
  end
@@ -0,0 +1,22 @@
1
+ require 'active_storage/service/s3_service'
2
+
3
+ module ActiveStorage
4
+ class Service::GlibS3Service < Service::S3Service
5
+ attr_accessor :tagging
6
+
7
+ # This is cause problem because S3 server ignore `x-amz-tagging` query params so it fails to tagging an object
8
+ # API: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Presigner.html#presigned_request-instance_method
9
+ # Detail about problem: https://github.com/aws/aws-sdk/issues/782
10
+ def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, custom_metadata: {})
11
+ instrument :url, key: key do |payload|
12
+ generated_url, headers = object_for(key).presigned_request :put, expires_in: expires_in.to_i,
13
+ content_type: content_type, content_length: content_length, content_md5: checksum,
14
+ metadata: custom_metadata, whitelist_headers: ['content-length'], tagging: tagging, **upload_options
15
+
16
+ payload[:url] = generated_url
17
+
18
+ [generated_url, headers]
19
+ end
20
+ end
21
+ end
22
+ end
data/lib/glib/engine.rb CHANGED
@@ -2,13 +2,6 @@ module Glib
2
2
  module Web
3
3
  class Engine < ::Rails::Engine
4
4
  # isolate_namespace Glib::Web
5
-
6
- # modify direct upload
7
- config.to_prepare do
8
- require_relative 's3_service'
9
- require_relative 'blob'
10
- require_relative 'direct_uploads_controller'
11
- end
12
5
  end
13
6
  end
14
7
  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: 4.1.4
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
@@ -14,16 +14,16 @@ dependencies:
14
14
  name: activestorage
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 5.2.3
19
+ version: '7.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 5.2.3
26
+ version: '7.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pundit
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -56,16 +56,30 @@ dependencies:
56
56
  name: actioncable
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 6.0.1
61
+ version: '7.0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '7.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: js_regex
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.11'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: 6.0.1
82
+ version: '3.11'
69
83
  description:
70
84
  email: ''
71
85
  executables: []
@@ -86,6 +100,7 @@ files:
86
100
  - app/controllers/concerns/glib/json/traversal.rb
87
101
  - app/controllers/concerns/glib/json/ui.rb
88
102
  - app/controllers/concerns/glib/json/validation.rb
103
+ - app/controllers/glib/glib_direct_uploads_controller.rb
89
104
  - app/controllers/glib/home_controller.rb
90
105
  - app/helpers/glib/app_feature_support_helper.rb
91
106
  - app/helpers/glib/dynamic_images_helper.rb
@@ -134,6 +149,7 @@ files:
134
149
  - app/models/glib/active_storage/attachment.rb
135
150
  - app/models/glib/active_storage/blob.rb
136
151
  - app/models/glib/application_record.rb
152
+ - app/models/glib/dummy_job_application.rb
137
153
  - app/models/glib/dynamic_text_record.rb
138
154
  - app/models/glib/text.rb
139
155
  - app/policies/glib/application_policy.rb
@@ -301,6 +317,7 @@ files:
301
317
  - app/views/layouts/json_ui/no_custom.html.erb
302
318
  - app/views/layouts/json_ui/renderer.html.erb
303
319
  - config/routes.rb
320
+ - lib/active_storage/service/glib_s3_service.rb
304
321
  - lib/generators/glib/install_generator.rb
305
322
  - lib/generators/templates/20191017062519_create_texts.rb
306
323
  - lib/generators/templates/20191024063257_add_scope_to_texts.rb
@@ -309,9 +326,7 @@ files:
309
326
  - lib/generators/templates/database.yml
310
327
  - lib/generators/templates/dynamic_text.rb
311
328
  - lib/glib-web.rb
312
- - lib/glib/blob.rb
313
329
  - lib/glib/crypt/utils.rb
314
- - lib/glib/direct_uploads_controller.rb
315
330
  - lib/glib/dynamic_text.rb
316
331
  - lib/glib/dynamic_text/config.rb
317
332
  - lib/glib/engine.rb
@@ -329,7 +344,6 @@ files:
329
344
  - lib/glib/json_crawler/http.rb
330
345
  - lib/glib/json_crawler/router.rb
331
346
  - lib/glib/mailer_tester.rb
332
- - lib/glib/s3_service.rb
333
347
  - lib/glib/test_helpers.rb
334
348
  - lib/glib/time_freezable_mailer.rb
335
349
  - lib/glib/time_returning_mailer.rb
data/lib/glib/blob.rb DELETED
@@ -1,23 +0,0 @@
1
- ::ActiveStorage::Blob.class_eval do
2
- attr_accessor :tagging
3
-
4
- # removing custom_metadata and add tagging
5
- def service_headers_for_direct_upload
6
- service.headers_for_direct_upload key, filename: filename, content_type: content_type, content_length: byte_size, checksum: checksum, tagging: tagging
7
- end
8
- def service_url_for_direct_upload(expires_in: ActiveStorage.service_urls_expire_in)
9
- service.url_for_direct_upload key, expires_in: expires_in, content_type: content_type, content_length: byte_size, checksum: checksum, custom_metadata: custom_metadata, tagging: tagging
10
- end
11
-
12
- class << self
13
- def create_before_direct_upload!(key: nil, filename:, byte_size:, checksum:, content_type: nil, metadata: nil, service_name: nil, record: nil, prefix: nil, tagging: nil)
14
- key_name = key || generate_unique_secure_token
15
- if prefix.present?
16
- key_name = "#{prefix}/#{key_name}"
17
- end
18
- blob = create! key: key_name, filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type, metadata: metadata, service_name: service_name
19
- blob.tagging = tagging
20
- blob
21
- end
22
- end
23
- end
@@ -1,32 +0,0 @@
1
- ::ActiveStorage::DirectUploadsController.class_eval do
2
- # include Rails.application.routes.url_helpers
3
- before_action :authenticate_user!
4
-
5
- rescue_from StandardError do |e|
6
- if !Rails.env.production?
7
- raise e
8
- end
9
- render json: { message: 'Upload failed' }, status: 500
10
- end
11
-
12
- rescue_from Glib::Auth::Policy::UnauthorizedError do
13
- render json: { message: 'Forbidden' }, status: 403
14
- end
15
-
16
- rescue_from ActionController::InvalidAuthenticityToken do
17
- render json: { message: 'Session expired. Please refresh page' }, status: 401
18
- end
19
-
20
- private
21
- def blob_args
22
- params.require(:blob).permit(:filename, :byte_size, :checksum, :content_type, :prefix, :tagging, metadata: {}).to_h.symbolize_keys
23
- end
24
-
25
- def authenticate_user!
26
- current_user.present? ? nil : raise_error
27
- end
28
-
29
- def raise_error
30
- raise Glib::Auth::Policy::UnauthorizedError
31
- end
32
- end
@@ -1,30 +0,0 @@
1
- require 'active_storage/service/s3_service'
2
-
3
- ::ActiveStorage::Service::S3Service.class_eval do
4
- attr_reader :headers_for_request
5
-
6
- # Change presigned_url to presigned_request
7
- # appearently presigned_url hoist all header `x-amz-` to query params.
8
- # This is cause problem because S3 server ignore `x-amz-tagging` query params so it fails to tagging an object
9
- # API: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Presigner.html#presigned_request-instance_method
10
- # Detail about problem: https://github.com/aws/aws-sdk/issues/782
11
- def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, tagging: nil, custom_metadata: {})
12
- instrument :url, key: key do |payload|
13
- generated_url, headers = object_for(key).presigned_request :put, expires_in: expires_in.to_i,
14
- content_type: content_type, content_length: content_length, content_md5: checksum,
15
- metadata: custom_metadata, whitelist_headers: ['content-length'], tagging: tagging, **upload_options
16
-
17
- payload[:url] = generated_url
18
- @headers_for_request = headers
19
-
20
- generated_url
21
- end
22
- end
23
-
24
- def headers_for_direct_upload(key, content_type:, checksum:, filename: nil, disposition: nil, tagging: nil, custom_metadata: {}, **)
25
- content_disposition = content_disposition_with(type: disposition, filename: filename) if filename
26
-
27
- headers = { 'Content-Type' => content_type, 'Content-MD5' => checksum, 'Content-Disposition' => content_disposition, **custom_metadata_headers(custom_metadata) }
28
- headers.merge(headers_for_request)
29
- end
30
- end