mobile_workflow 0.7.4 → 0.7.8

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +83 -0
  3. data/app/controllers/concerns/mobile_workflow/s3_storable.rb +14 -11
  4. data/app/controllers/mobile_workflow/sns_notifications_controller.rb +14 -37
  5. data/app/jobs/mobile_workflow/add_attachment_job.rb +30 -0
  6. data/app/models/concerns/mobile_workflow/attachable.rb +32 -0
  7. data/app/models/concerns/mobile_workflow/displayable/steps/form.rb +70 -0
  8. data/app/models/concerns/mobile_workflow/displayable/steps/list.rb +15 -0
  9. data/app/models/concerns/mobile_workflow/displayable/steps/map.rb +11 -0
  10. data/app/models/concerns/mobile_workflow/displayable/steps/pie_chart.rb +11 -0
  11. data/app/models/concerns/mobile_workflow/displayable/steps/question.rb +25 -0
  12. data/app/models/concerns/mobile_workflow/displayable/steps/stack.rb +75 -0
  13. data/app/models/concerns/mobile_workflow/displayable/steps/styled_content/grid.rb +30 -0
  14. data/app/models/concerns/mobile_workflow/displayable/steps/styled_content/stack.rb +40 -0
  15. data/app/models/concerns/mobile_workflow/displayable.rb +17 -146
  16. data/config/initializers/add_frozen_string_literal.rb +19 -0
  17. data/lib/generators/mobile_workflow/install/install_generator.rb +17 -1
  18. data/lib/generators/mobile_workflow/install/templates/Gemfile.erb +24 -7
  19. data/lib/generators/mobile_workflow/install/templates/api_controller.rb.erb +1 -1
  20. data/lib/generators/mobile_workflow/install/templates/app/helpers/application_helper.rb +1 -2
  21. data/lib/generators/mobile_workflow/install/templates/{ability.rb → app/models/ability.rb} +1 -1
  22. data/lib/generators/mobile_workflow/install/templates/app/models/application_record.rb +3 -2
  23. data/lib/generators/mobile_workflow/install/templates/config/initializers/mobile_workflow_rollbar.rb +7 -0
  24. data/lib/generators/mobile_workflow/install/templates/deserializer.rb.erb +13 -0
  25. data/lib/generators/mobile_workflow/install/templates/deserializer_spec.rb.erb +27 -0
  26. data/lib/generators/mobile_workflow/install/templates/seeds.rb.erb +1 -1
  27. data/lib/generators/mobile_workflow/install/templates/sessions_controller.rb.erb +3 -4
  28. data/lib/generators/mobile_workflow/install/templates/user.rb.erb +4 -0
  29. data/lib/generators/mobile_workflow/model_generator.rb +9 -2
  30. data/lib/generators/mobile_workflow/templates/controller.rb.erb +7 -5
  31. data/lib/generators/mobile_workflow/templates/controller_spec.rb.erb +17 -9
  32. data/lib/generators/mobile_workflow/templates/model.rb.erb +17 -2
  33. data/lib/mobile_workflow/cli/app_builder.rb +21 -4
  34. data/lib/mobile_workflow/cli/app_server_generator.rb +3 -1
  35. data/lib/mobile_workflow/displayable.rb +9 -0
  36. data/lib/mobile_workflow/engine.rb +7 -5
  37. data/lib/mobile_workflow/version.rb +1 -1
  38. data/lib/mobile_workflow.rb +1 -0
  39. metadata +53 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 793d6e2517f66a2a0eb664541c4b97a37b5bb8c3a6e55e007b8d0c9947e7dbfc
4
- data.tar.gz: 12288b78b8f962f7b99ac47f7f3eaaf8c3390a474672ee943f5ac86123e47f0d
3
+ metadata.gz: 652ebd5ca3b96f993ee3c6a7bc57863eaa70119fb41aca0586a02430795bd0d1
4
+ data.tar.gz: ab8191098d6eeed1825fd8fd1a2debb5c4ae762cfb887362793e96a7d62278ae
5
5
  SHA512:
6
- metadata.gz: f9a5594c34e7dfbfd71dd239aca140018fe9fef0ffcf55b356000450b9e84e9615457c62edc43fe33ebd67b2d3665b02c15ff893079a2e76b387c9811a60bfa9
7
- data.tar.gz: 7925c77c229f26fd42b8639038ff74b4f89fa6bfe1a1c7662309f8ae4dce1ca27046bb60e9e5640f5e6360a6b30c2ec666a801048e731213576ab08d3b78d21d
6
+ metadata.gz: 4b4acc6286656e349602808ac82b6049da2e8ef3d721fba490346d0f003701c9efdde26fdcf9b2352df2ff3bc34d40bec571f941701129298baa02d8f356ad29
7
+ data.tar.gz: 7a1cfa5d993b5bfc91f98ede6e6c7000990ffd149bafe18c0f4232e80462a7fd9d0cea0eec2c020437e6cdb3dce7a14e747e4b4dfe6e4cd6886b4b28fc0905f3
data/README.md CHANGED
@@ -26,6 +26,89 @@ Or install it yourself as:
26
26
  $ gem install mobile_workflow
27
27
  ```
28
28
 
29
+ ## Upgrade to version 0.7.7 or higher
30
+ The following utility methods have changed their parameters:
31
+
32
+ ```ruby
33
+ # app/models/concerns/mobile_workflow/displayable/steps/styled_content/grid.rb#20
34
+ def mw_grid_item(id: self.id, text:, detail_text: nil, preview_url: nil)
35
+ raise 'Missing id' if id.nil?
36
+ raise 'Missing text' if text.nil?
37
+
38
+ { id: id, text: text, type: :item, detailText: detail_text, imageURL: preview_url }.compact
39
+ end
40
+
41
+ # app/models/concerns/mobile_workflow/displayable/steps/styled_content/stack.rb#20
42
+ def mw_stack_list_item(id:, text:, detail_text: nil, preview_url: nil)
43
+ raise 'Missing id' if id.nil?
44
+ raise 'Missing text' if text.nil?
45
+
46
+ { id: id.to_s, text: text, detailText: detail_text, type: :listItem, imageURL: preview_url }.compact
47
+ end
48
+
49
+ # app/models/concerns/mobile_workflow/displayable/steps/list.rb#5
50
+ def mw_list_item(id: self.id, text:, detail_text: nil, sf_symbol_name: nil, material_icon_name: nil, preview_url: nil)
51
+ { id: id, text: text, detailText: detail_text, sfSymbolName: sf_symbol_name, materialIconName: material_icon_name, imageURL: preview_url }.compact
52
+ end
53
+
54
+ # app/models/concerns/mobile_workflow/displayable/steps/stack.rb#26
55
+ def mw_display_video(preview_url:, attachment_url:)
56
+ {type: :video, previewURL: preview_url, url: attachment_url}
57
+ end
58
+
59
+ # app/models/concerns/mobile_workflow/displayable/steps/stack.rb#11
60
+ def mw_display_image(preview_url:, attachment_url:, content_mode: :scale_aspect_fill)
61
+ validate_content_mode!(content_mode)
62
+
63
+ {type: :image, contentMode: camelcase_converter(content_mode.to_s, first_letter: :lower), previewURL: preview_url, url: attachment_url}
64
+ end
65
+ ```
66
+
67
+ All URLs MUST now be explicitly sent as arguments to the above methods, which means they must be previously set. If not, the methods will not work.
68
+
69
+ In order to support projects using `ActiveStorage`, there is a new model concern `MobileWorkflow::Attachable` that provides a few helpers. This is what you can do to upgrade if you use ActiveStorage (otherwise the helpers must be manually created):
70
+
71
+ 1. Include the concern in the `ApplicationRecord` class, together with `MobileWorkflow::Displayable`:
72
+
73
+ ```ruby
74
+ class ApplicationRecord < ActiveRecord::Base
75
+ include MobileWorkflow::Attachable
76
+ include MobileWorkflow::Displayable
77
+ end
78
+ ```
79
+
80
+ 2. Once included, the following helpers will be available, so use them to generate the intended URLs:
81
+
82
+ ```ruby
83
+ def preview_url(attachment, options: { resize_to_fill: [200, 200] })
84
+ return nil unless attachment.attached?
85
+
86
+ if attachment.image?
87
+ rails_representation_url(attachment.variant(options), host: heroku_attachment_host)
88
+ elsif attachment.previewable?
89
+ rails_representation_url(attachment.preview(options), host: heroku_attachment_host)
90
+ else
91
+ return nil
92
+ end
93
+ end
94
+
95
+ def attachment_url(attachment)
96
+ return nil unless attachment.attached?
97
+
98
+ rails_blob_url(attachment, host: heroku_attachment_host)
99
+ end
100
+ ```
101
+
102
+ Example of use:
103
+ ```ruby
104
+ # Old method call
105
+ mw_list_item(text: 'John Doe', detail_text: 'Company Name', image_attachment: <ActiveStorage::Attached::One>, image_url: 'https://test.org/preview')
106
+
107
+ # New method call
108
+ preview_url = preview_url(<ActiveStorage::Attached::One>, options: { resize_to_fill: [200, 200] }) || 'https://test.org/preview'
109
+ mw_list_item(text: 'John Doe', detail_text: 'Company Name', preview_url: preview_url)
110
+ ```
111
+
29
112
  ## Contributing
30
113
  Contribution directions go here.
31
114
 
@@ -1,19 +1,23 @@
1
+ require 'aws-sdk-s3'
2
+
1
3
  module MobileWorkflow
2
4
  module S3Storable
3
5
  if Object.const_defined?("Aws::S3")
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  def binary_urls(object)
7
- return unless params["binaries"]
9
+ return unless params[:binaries]
8
10
 
9
- params["binaries"].map do |binary|
10
- object_attribute = binary["identifier"]
11
- extension = binary["mimetype"].split('/')[1] # i.e. image/jpg --> jpg, video/mp4 --> mp4
12
-
11
+ params[:binaries].map do |binary|
12
+ identifier = binary[:identifier]
13
+ object_attribute = identifier.split(".")[0] # ensure extension doesnt get added here
14
+ extension = binary[:mimetype].split('/')[1] # i.e. image/jpg --> jpg, video/mp4 --> mp4
15
+ metadata = binary[:metadata]
16
+
13
17
  {
14
- "identifier" => binary["identifier"],
15
- "url" => presigned_url("#{object.class.name.underscore}/#{object.id}/#{object_attribute}/#{s3_object_uuid}.#{extension}"),
16
- "method" => "PUT"
18
+ identifier: identifier,
19
+ url: presigned_url("#{object.class.name.underscore}/#{object.id}/#{object_attribute}/#{s3_object_uuid}.#{extension}", metadata: metadata),
20
+ method: "PUT"
17
21
  }
18
22
  end
19
23
  end
@@ -23,8 +27,8 @@ module MobileWorkflow
23
27
  SecureRandom.uuid
24
28
  end
25
29
 
26
- def presigned_url(key)
27
- presigner.presigned_url(:put_object, bucket: ENV['AWS_BUCKET_NAME'], key: key, metadata: {})
30
+ def presigned_url(key, metadata: nil)
31
+ presigner.presigned_url(:put_object, bucket: ENV['AWS_BUCKET_NAME'], key: key, metadata: metadata)
28
32
  end
29
33
 
30
34
  def presigner
@@ -34,7 +38,6 @@ module MobileWorkflow
34
38
  def s3_client
35
39
  Aws::S3::Client.new(region: ENV['AWS_REGION'], access_key_id: ENV['AWS_ACCESS_ID'], secret_access_key: ENV['AWS_SECRET_KEY'])
36
40
  end
37
-
38
41
  end
39
42
  end
40
43
  end
@@ -1,3 +1,5 @@
1
+ require 'aws-sdk-sns'
2
+
1
3
  module MobileWorkflow
2
4
  class SnsNotificationsController < ActionController::API
3
5
  if Object.const_defined?("Aws::S3") && Object.const_defined?("Aws::SNS")
@@ -10,26 +12,16 @@ module MobileWorkflow
10
12
  when 'SubscriptionConfirmation'
11
13
  confirm_subscription ? (head :ok) : (head :bad_request)
12
14
  else
13
- add_attachment
15
+ AddAttachmentJob.perform_now(object, object_key, attribute_name)
16
+ head :ok
14
17
  end
18
+ rescue NameError => e
19
+ Rails.logger.warn "Error attaching object: #{e.message}"
20
+ rescue ActiveRecord::RecordNotFound
21
+ head :not_found
15
22
  end
16
23
 
17
24
  private
18
- def add_attachment
19
- begin
20
- @object = find_object
21
- @object.send("#{attribute_name}=",active_record_blob)
22
- if @object.save
23
- head :ok
24
- else
25
- Rails.logger.warn "Error saving object: #{@object} #{object.errors.full_messages}"
26
- head :unprocessable_entity
27
- end
28
- rescue NameError => e
29
- Rails.logger.warn "Error attaching object: #{e.message}"
30
- head :unprocessable_entity
31
- end
32
- end
33
25
 
34
26
  def verify_request_authenticity
35
27
  head :unauthorized if raw_post.blank?
@@ -37,22 +29,11 @@ module MobileWorkflow
37
29
  #head :unauthorized if raw_post.blank? || !message_verifier.authentic?(raw_post) # Not working
38
30
  end
39
31
 
40
- def active_record_blob
41
- s3_object = s3_bucket.object(object_key)
42
- checksum_base64 = checksum_base64(object_key, s3_object)
43
- ActiveStorage::Blob.create! key: s3_object.key, filename: s3_object.key, byte_size: s3_object.size, checksum: checksum_base64, content_type: s3_object.content_type
44
- end
45
-
46
- def checksum_base64(object_key, s3_object)
47
- path = Tempfile.new(object_key).path
48
- s3_object.download_file(path)
49
- file = File.new(path)
50
- Digest::MD5.file(file).base64digest
51
- end
52
-
53
- def find_object
54
- object_class_name, object_id = key_identifiers
55
- object_class_name.camelcase.constantize.find(object_id.to_i)
32
+ def object
33
+ @object ||= begin
34
+ object_class_name, object_id = key_identifiers
35
+ object_class_name.camelcase.constantize.find(object_id.to_i)
36
+ end
56
37
  end
57
38
 
58
39
  def attribute_name
@@ -91,11 +72,7 @@ module MobileWorkflow
91
72
  Rails.logger.warn(e.message)
92
73
  return false
93
74
  end
94
-
95
- def s3_bucket
96
- Aws::S3::Resource.new(region: ENV['AWS_REGION'], access_key_id: ENV['AWS_ACCESS_ID'], secret_access_key: ENV['AWS_SECRET_KEY']).bucket(ENV['AWS_BUCKET_NAME'])
97
- end
98
-
75
+
99
76
  def sns_client
100
77
  Aws::SNS::Client.new(region: ENV['AWS_REGION'], access_key_id: ENV['AWS_ACCESS_ID'], secret_access_key: ENV['AWS_SECRET_KEY'])
101
78
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MobileWorkflow
4
+ class AddAttachmentJob < ApplicationJob
5
+ def perform(object, object_key, attribute_name)
6
+ object.send("#{attribute_name}=", active_record_blob_from_s3(object_key))
7
+ Rails.logger.warn "Error saving object: #{object} #{object.errors.full_messages}" unless object.save
8
+ rescue NoMethodError => e
9
+ Rails.logger.warn "Error attaching object: #{e.message}"
10
+ end
11
+
12
+ private
13
+
14
+ def active_record_blob_from_s3(object_key)
15
+ # etag cannot be used as the MD5 checksum when doing multi-part uploads
16
+ s3_object = s3_bucket.object(object_key)
17
+ base64_digest = hex_to_base64_digest(s3_object.etag.delete('"'))
18
+ ActiveStorage::Blob.create! key: s3_object.key, filename: s3_object.key, byte_size: s3_object.size,
19
+ checksum: base64_digest, content_type: s3_object.content_type
20
+ end
21
+
22
+ def s3_bucket
23
+ Aws::S3::Resource.new(region: ENV['AWS_REGION'], access_key_id: ENV['AWS_ACCESS_ID'], secret_access_key: ENV['AWS_SECRET_KEY']).bucket(ENV['AWS_BUCKET_NAME'])
24
+ end
25
+
26
+ def hex_to_base64_digest(hexdigest)
27
+ [[hexdigest].pack('H*')].pack('m0')
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ module MobileWorkflow
2
+ module Attachable
3
+ extend ActiveSupport::Concern
4
+ include Rails.application.routes.url_helpers
5
+
6
+ def preview_url(attachment, options: { resize_to_fill: [200, 200] })
7
+ return nil unless attachment.attached?
8
+
9
+ if attachment.image?
10
+ rails_representation_url(attachment.variant(options), host: heroku_attachment_host)
11
+ elsif attachment.previewable?
12
+ rails_representation_url(attachment.preview(options), host: heroku_attachment_host)
13
+ else
14
+ return nil
15
+ end
16
+ end
17
+
18
+ def attachment_url(attachment)
19
+ return nil unless attachment.attached?
20
+
21
+ rails_blob_url(attachment, host: heroku_attachment_host)
22
+ end
23
+
24
+ private
25
+
26
+ def heroku_attachment_host
27
+ # TODO: MBS - move this to a configuration property
28
+ app_name = Rails.env.test? ? 'test-app' : ENV.fetch('HEROKU_APP_NAME')
29
+ "https://#{app_name}.herokuapp.com"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,70 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ module Steps
4
+ module Form
5
+ def mw_form_section(label:, identifier:)
6
+ raise 'Missing label' if label.nil?
7
+ raise 'Missing identifier' if identifier.nil?
8
+
9
+ { item_type: :section, label: label, identifier: identifier }
10
+ end
11
+
12
+ def mw_form_multiple_selection(label:, identifier:, multiple_selection_options:, selection_type: :single, optional: false, show_other_option: false)
13
+ raise 'Missing label' if label.nil?
14
+ raise 'Missing identifier' if identifier.nil?
15
+ raise 'Missing multiple selection options' if multiple_selection_options.nil?
16
+
17
+ { item_type: :multiple_selection, label: label, identifier: identifier, multiple_selection_options: multiple_selection_options, selection_type: selection_type, optional: optional, show_other_option: show_other_option }
18
+ end
19
+
20
+ def mw_form_multiple_selection_options(text:, hint: nil, is_pre_selected: false)
21
+ raise 'Missing text' if text.nil?
22
+
23
+ { text: text, hint: hint, isPreSelected: is_pre_selected }
24
+ end
25
+
26
+ def mw_form_number(label:, identifier:, placeholder: nil, optional: false, symbol_position: :leading, default_text_answer: nil, hint: nil)
27
+ raise 'Missing label' if label.nil?
28
+ raise 'Missing identifier' if identifier.nil?
29
+
30
+ { item_type: :number, number_type: :number, label: label, identifier: identifier, placeholder: placeholder, optional: optional, symbol_position: symbol_position, default_text_answer: default_text_answer, hint: hint }
31
+ end
32
+
33
+ def mw_form_text(label:, identifier:, placeholder: nil, optional: false, multiline: false, default_text_answer: nil)
34
+ raise 'Missing label' if label.nil?
35
+ raise 'Missing identifier' if identifier.nil?
36
+
37
+ { item_type: :text, label: label, identifier: identifier, placeholder: placeholder, optional: optional, multiline: multiline, default_text_answer: default_text_answer }
38
+ end
39
+
40
+ def mw_form_date(label:, identifier:, optional: false, default_text_answer: nil)
41
+ raise 'Missing label' if label.nil?
42
+ raise 'Missing identifier' if identifier.nil?
43
+
44
+ { item_type: :date, date_type: :calendar, label: label, identifier: identifier, optional: optional, default_text_answer: default_text_answer }
45
+ end
46
+
47
+ def mw_form_time(label:, identifier:, optional: false, default_text_answer: nil)
48
+ raise 'Missing label' if label.nil?
49
+ raise 'Missing identifier' if identifier.nil?
50
+
51
+ { item_type: :time, label: label, identifier: identifier, optional: optional, default_text_answer: default_text_answer }
52
+ end
53
+
54
+ def mw_form_email(label:, identifier:, placeholder: nil, optional: false, default_text_answer: nil)
55
+ raise 'Missing label' if label.nil?
56
+ raise 'Missing identifier' if identifier.nil?
57
+
58
+ { item_type: :email, label: label, identifier: identifier, placeholder: placeholder, optional: optional, default_text_answer: default_text_answer }
59
+ end
60
+
61
+ def mw_form_password(label:, identifier:, placeholder: nil, optional: false, default_text_answer: nil, hint: nil)
62
+ raise 'Missing label' if label.nil?
63
+ raise 'Missing identifier' if identifier.nil?
64
+
65
+ { item_type: :secure, label: label, identifier: identifier, placeholder: placeholder, optional: optional, default_text_answer: default_text_answer, hint: hint }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,15 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ module Steps
4
+ module List
5
+ def mw_list_item(id: self.id, text:, detail_text: nil, sf_symbol_name: nil, material_icon_name: nil, preview_url: nil)
6
+ { id: id, text: text, detailText: detail_text, sfSymbolName: sf_symbol_name, materialIconName: material_icon_name, imageURL: preview_url }.compact
7
+ end
8
+
9
+ def mw_list_search_suggestion(id: self.id, text:, section_name:, sf_symbol_name: nil)
10
+ {id: id.to_s, text: text, sectionName: section_name, sfSymbolName: sf_symbol_name}.compact
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ module Steps
4
+ module Map
5
+ def mw_map_item(id: self.id, text:, detail_text: nil, latitude:, longitude:)
6
+ {id: id.to_s, text: text, detailText: detail_text, latitude: latitude, longitude: longitude}.compact
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ module Steps
4
+ module PieChart
5
+ def mw_pie_chart_item(id: self.id, label:, value:)
6
+ {id: id, label: label, value: value}.compact
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ module Steps
4
+ module Question
5
+ QUESTION_STYLES = [:single_choice, :multiple_choice]
6
+
7
+ def mw_text_choice_question(question:, style:, text_choices:)
8
+ raise 'Missing question' if question.empty?
9
+ raise 'Text Choices should be a hash' unless text_choices.is_a?(Hash)
10
+
11
+ validate_question_style!(style)
12
+
13
+ text_choices_a = text_choices.map{|k, v| {_class: "ORKTextChoice", exclusive: false, text: k, value: v} }.to_a
14
+ { question: question, answerFormat: { _class: "ORKTextChoiceAnswerFormat", style: camelcase_converter(style.to_s, first_letter: :lower), textChoices: text_choices_a}}
15
+ end
16
+
17
+ private
18
+
19
+ def validate_question_style!(style)
20
+ raise 'Unknown style' unless QUESTION_STYLES.include?(style)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,75 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ module Steps
4
+ module Stack
5
+ CONTENT_MODE_OPTIONS = [:scale_aspect_fill, :scale_aspect_fit]
6
+
7
+ def mw_display_text(text:, label: nil)
8
+ {type: :text, label: label, text: text.to_s}.compact
9
+ end
10
+
11
+ def mw_display_image(preview_url:, attachment_url:, content_mode: :scale_aspect_fill)
12
+ validate_content_mode!(content_mode)
13
+
14
+ {type: :image, contentMode: camelcase_converter(content_mode.to_s, first_letter: :lower), previewURL: preview_url, url: attachment_url}
15
+ end
16
+
17
+ def mw_display_unsplash_image(image_url)
18
+ if image_url.start_with? "https://unsplash.com/photos"
19
+ unsplash_id = image_url.split('/').last
20
+ image_url = "https://source.unsplash.com/#{unsplash_id}/800x600"
21
+ end
22
+
23
+ {type: :image, previewURL: image_url, url: image_url}.compact
24
+ end
25
+
26
+ def mw_display_video(preview_url:, attachment_url:)
27
+ {type: :video, previewURL: preview_url, url: attachment_url}
28
+ end
29
+
30
+ def mw_display_button(label:, style: :primary, on_success: :forward, sf_symbol_name: nil, material_icon_name: nil)
31
+ validate_on_success!(on_success)
32
+ validate_button_style!(style)
33
+
34
+ {type: :button, label: label, style: style, onSuccess: on_success, sfSymbolName: sf_symbol_name, materialIconName: material_icon_name}.compact
35
+ end
36
+
37
+ def mw_display_delete_button(url:, label: "Delete", method: :delete, style: :danger, on_success: :backward)
38
+ validate_on_success!(on_success)
39
+ validate_button_style!(style)
40
+
41
+ {type: :button, label: label, url: url, method: method, style: style, onSuccess: on_success, sfSymbolName: 'trash', materialIconName: 'delete'}.compact
42
+ end
43
+
44
+ def mw_display_url_button(url:, label:, method: :put, style: :primary, confirm_title: nil, confirm_text: nil, on_success: :reload, sf_symbol_name: nil, material_icon_name: nil)
45
+ validate_on_success!(on_success)
46
+ validate_button_style!(style)
47
+
48
+ {type: :button, label: label, url: url, method: method, style: style, confirmTitle: confirm_title, confirmText: confirm_text, onSuccess: on_success, sfSymbolName: sf_symbol_name, materialIconName: material_icon_name}.compact
49
+ end
50
+ alias_method :mw_display_button_for_url, :mw_display_url_button
51
+
52
+ def mw_display_system_url_button(label:, apple_system_url: nil, android_deep_link: nil, style: :primary, sf_symbol_name: nil, material_icon_name: nil)
53
+ validate_button_style!(style)
54
+ raise 'Invalid android_deep_link' if android_deep_link && !android_deep_link.start_with?('http')
55
+
56
+ {type: :button, label: label, appleSystemURL: apple_system_url, androidDeepLink: android_deep_link, style: style, sfSymbolName: sf_symbol_name, materialIconName: material_icon_name}.compact
57
+ end
58
+ alias_method :mw_display_button_for_system_url, :mw_display_system_url_button
59
+
60
+ def mw_display_modal_workflow_button(label:, modal_workflow_name:, style: :primary, on_success: :none, sf_symbol_name: nil, material_icon_name: nil)
61
+ validate_on_success!(on_success)
62
+ validate_button_style!(style)
63
+
64
+ {type: :button, label: label, modalWorkflow: modal_workflow_name, style: style, onSuccess: on_success, sfSymbolName: sf_symbol_name, materialIconName: material_icon_name}.compact
65
+ end
66
+ alias_method :mw_display_button_for_modal_workflow, :mw_display_modal_workflow_button
67
+
68
+ private
69
+ def validate_content_mode!(on_success)
70
+ raise 'Unknown content_mode' unless CONTENT_MODE_OPTIONS.include?(on_success)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,30 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ module Steps
4
+ module StyledContent
5
+ module Grid
6
+ def mw_grid_large_section(id:, text:)
7
+ raise 'Missing id' if id.nil?
8
+ raise 'Missing text' if text.nil?
9
+
10
+ { id: id, text: text, type: :largeSection }
11
+ end
12
+
13
+ def mw_grid_small_section(id:, text:)
14
+ raise 'Missing id' if id.nil?
15
+ raise 'Missing text' if text.nil?
16
+
17
+ { id: id, text: text, type: :smallSection }
18
+ end
19
+
20
+ def mw_grid_item(id: self.id, text:, detail_text: nil, preview_url: nil)
21
+ raise 'Missing id' if id.nil?
22
+ raise 'Missing text' if text.nil?
23
+
24
+ { id: id, text: text, type: :item, detailText: detail_text, imageURL: preview_url }.compact
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ module MobileWorkflow
2
+ module Displayable
3
+ module Steps
4
+ module StyledContent
5
+ module Stack
6
+ def mw_stack_title(id:, title:)
7
+ raise 'Missing id' if id.nil?
8
+ raise 'Missing title' if title.nil?
9
+
10
+ { id: id, title: title, type: :title }
11
+ end
12
+
13
+ def mw_stack_text(id:, text:)
14
+ raise 'Missing id' if id.nil?
15
+ raise 'Missing text' if text.nil?
16
+
17
+ { id: id, text: text, type: :text }
18
+ end
19
+
20
+ def mw_stack_list_item(id:, text:, detail_text: nil, preview_url: nil)
21
+ raise 'Missing id' if id.nil?
22
+ raise 'Missing text' if text.nil?
23
+
24
+ { id: id.to_s, text: text, detailText: detail_text, type: :listItem, imageURL: preview_url }.compact
25
+ end
26
+
27
+ def mw_stack_button(id:, label:, url: nil, method: :nil, on_success: :none, style: :primary, modal_workflow_name: nil, link_url: nil, sf_symbol_name: nil, apple_system_url: nil, android_deep_link: nil, confirm_title: nil, confirm_text: nil)
28
+ raise 'Missing id' if id.nil?
29
+ raise 'Missing label' if label.nil?
30
+
31
+ validate_on_success!(on_success)
32
+ validate_button_style!(style)
33
+
34
+ { id: id, type: :button, label: label, url: url, method: method, onSuccess: on_success, style: style, modalWorkflow: modal_workflow_name, linkURL: link_url, sfSymbolName: sf_symbol_name, appleSystemURL: apple_system_url, androidDeepLink: android_deep_link, confirmTitle: confirm_title, confirmText: confirm_text }.compact
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end