habarico 7.3.0.pre.beta.2 → 7.3.0.pre.beta.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da37ba29d89a66e75d207995933a5034fc8f404d03e95e701b301b4e37964adb
4
- data.tar.gz: bc191e762ed87d1627d97088325ae61a32da42e314f32592e1ee449de8f67e05
3
+ metadata.gz: 6be967b0f84be5812add3427f8150fc6d8b01909b1441ef70a04a5579f737587
4
+ data.tar.gz: d16af3d641bcc6b8a84f3663c38ade72c6ae96666ad5987258948bb70b0e9e9c
5
5
  SHA512:
6
- metadata.gz: f959dcd0c250c92e576c639be808ae7cb0af79bf3597b2b1b7ba9237f7ce6a44ae6d366f980eebd43fdb5a8f5caadcc223705c7b8bb2dd2bfc304ee3f486eb30
7
- data.tar.gz: d900620185f6b9d0eb913a7ef5cd593beaa4c754d212c97ad44495ca4d7ed6d4867b93613cf8884e6f3696d9c8a63a70f608274275013b960a9022304dde2cc4
6
+ metadata.gz: '078b5e0d648bed830162d2850b971f19b2cca505928d223ac4242939f017985896d04b594f69528e4bc3efa69e2b212d6c2638b425b8bfcb2ba5730f61f78a12'
7
+ data.tar.gz: db8b3494d1d9964aed2ab58d91ac6cd11bda53259d49779d5ff837dcdc5fd349dbca96c18677d55a15e071043ecd1172114cf85de63e068ee549c45b94a28eb5
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.3.0-beta.2
1
+ 7.3.0-beta.3
@@ -234,26 +234,32 @@ module Habarico
234
234
  }
235
235
  end
236
236
 
237
+ # Renders an `ActionResult`: `message`, `state` and `trigger_action` live under `meta`, and the
238
+ # response's own `data` is merged next to it. This is the shape the contract prescribes and the
239
+ # only one the frontend reads - it looks at `resp.data.meta` and nowhere else.
237
240
  def render_response(response)
238
- if response.action
239
- action = definition.normalized_actions.find { |a| a.name.to_s == response.action.to_s }
240
- if action
241
- resource_path = Habarico::ResourceService.instance.get_resource_path(controller_name)
242
- action_schema_generator = definition.action_schema_generator.new(definition, resource_path)
243
- trigger_action = action_schema_generator.generate(action, context).as_json.deep_compact(compactable: [nil, {}].freeze)
244
- end
245
- end
246
- render json: {
247
- state: response.state,
248
- message: response.message,
249
- trigger_action: trigger_action
250
- }.deep_compact
241
+ meta = {
242
+ 'message' => response.message,
243
+ 'state' => response.state,
244
+ 'trigger_action' => build_action_schema(response.action)&.as_json&.deep_compact(compactable: [nil, {}].freeze)
245
+ }.compact
246
+ render json: { 'meta' => meta }.merge(response.data.presence || {})
251
247
  end
252
248
 
253
249
  def get_trigger_action_schema(_record)
254
250
  nil # override in subclasses to return an ActionSchema instance
255
251
  end
256
252
 
253
+ # Builds the complete `Habarico::ActionSchema` of `action` - a declared action's name or a
254
+ # `Habarico::Action` - for `get_trigger_action_schema` or `Habarico::Response.new(action: ...)`.
255
+ # `record` builds the context from that record, `record_pk` and `reference` retarget the action.
256
+ def build_action_schema(action, record: nil, record_pk: nil, reference: nil)
257
+ resource_path = Habarico::ResourceService.instance.get_resource_path(controller_name)
258
+ definition.trigger_action_schema_generator
259
+ .new(definition, resource_path)
260
+ .generate(action, record ? _context(record) : context, record_pk: record_pk, reference: reference)
261
+ end
262
+
257
263
  # Checks the `order_by` query parameter against what this resource offers for sorting.
258
264
  #
259
265
  # The notation itself - `field:direction`, exactly one `:`, a lower-case `asc`/`desc` - and the
@@ -4,11 +4,16 @@ module Habarico
4
4
 
5
5
  attr_accessor :type, :label, :icon, :color, :is_detail, :name, :show_in_detail, :show_in_list,
6
6
  :confirm_dialog_title, :confirm_dialog_message, :permission
7
- attr_accessor :view_name, :view_mode, :dialog_width, :view_parameters, :view_keep_linked_parent # attributes for type = :view
8
- attr_accessor :endpoint_action_name, :endpoint_method, :endpoint_reference # attributes for type = :view or :resource
7
+ attr_accessor :view_name, :view_mode, :dialog_width, :view_parameters, :view_keep_linked_parent, :view_choices # attributes for type = :view
8
+ # `endpoint_record_pk` pins the action to one concrete record instead of the one in the
9
+ # context. It is what lets a trigger action point at a record of another resource - together
10
+ # with `endpoint_reference` it spells out the whole target, so neither side has to be guessed
11
+ # from the request the action ran on.
12
+ attr_accessor :endpoint_action_name, :endpoint_method, :endpoint_reference, :endpoint_record_pk # attributes for type = :view or :resource
9
13
  attr_accessor :is_background, :data # attributes for type = :resource
14
+ attr_accessor :after_save # attributes for type = :save
10
15
  attr_accessor :link_url, :link_target, :if # attributes for type = :link
11
- attr_accessor :upload_images_reference, :upload_images_target, :upload_images_accept, :upload_images_image_field # attributes for type = :"upload-images"
16
+ attr_accessor :upload_images_reference, :upload_images_target, :upload_images_accept, :upload_images_image_field, :upload_images_data # attributes for type = :"upload-images"
12
17
 
13
18
  end
14
19
  end
@@ -38,6 +38,7 @@ module Habarico
38
38
  :view_action_endpoint_parameters_generator, :view_action_parameters_generator,
39
39
  :confirm_dialog_properties_generator, :global_resource_action_schema_generator,
40
40
  :resource_action_schema_generator, :upload_images_action_parameters_generator,
41
+ :trigger_action_schema_generator,
41
42
 
42
43
  # Generator classes - endpoint
43
44
  :dynamic_render_options_generator, :method_schema_generator, :endpoints_schema_generator,
@@ -119,6 +120,7 @@ module Habarico
119
120
  @global_resource_action_schema_generator = Habarico::GlobalResourceActionSchemaGenerator
120
121
  @resource_action_schema_generator = Habarico::ResourceActionSchemaGenerator
121
122
  @upload_images_action_parameters_generator = Habarico::UploadImagesActionParametersGenerator
123
+ @trigger_action_schema_generator = Habarico::TriggerActionSchemaGenerator
122
124
 
123
125
  # Endpoint
124
126
  @dynamic_render_options_generator = Habarico::DynamicRenderOptionsGenerator
@@ -2,7 +2,14 @@ module Habarico
2
2
  class Response
3
3
  include DefinitionModel
4
4
 
5
- attr_accessor :message, :state, :action
5
+ # `action` is the follow-up action the frontend runs once it has this response. It accepts the
6
+ # name of an action declared in `actions`, a `Habarico::Action` built on the spot (an ad-hoc
7
+ # action the resource does not declare) or a complete `Habarico::ActionSchema` - see
8
+ # `Habarico::Controller#build_action_schema`.
9
+ #
10
+ # `data` is merged next to `meta` in the rendered `ActionResult`, which is where the contract
11
+ # allows an action to return a payload of its own.
12
+ attr_accessor :message, :state, :action, :data
6
13
 
7
14
  def initialize(params = {})
8
15
  @state = :success
@@ -97,8 +97,10 @@ module Habarico
97
97
 
98
98
  def generate_save(action, context)
99
99
  if action.type.to_sym == :save
100
+ # Either parameter on its own is worth sending: `after_save` changes where the form goes
101
+ # after the save, with no data to add to the record.
100
102
  data = Habarico::CallableHelper.resolve(action.data, context)
101
- save_action_parameters_generator.generate(action, context) unless data.nil?
103
+ save_action_parameters_generator.generate(action, context) unless data.nil? && action.after_save.nil?
102
104
  end
103
105
  end
104
106
 
@@ -22,7 +22,10 @@ module Habarico
22
22
  # ***********************************************************************
23
23
 
24
24
  def generate_path(action, context)
25
- return nil if Habarico::ActionHelper.is_standard_action?(action)
25
+ # A standard action of the current resource needs no path - the frontend already knows the
26
+ # endpoint. One that names its own target does: the path is what points the call at the
27
+ # other resource or record.
28
+ return nil if Habarico::ActionHelper.is_standard_action?(action) && !Habarico::ActionHelper.has_explicit_target?(action)
26
29
  url_prefix = Habarico::Config.routing_url_prefix.trim('/')
27
30
  result = !url_prefix.blank? ? "/#{url_prefix}" : ''
28
31
 
@@ -30,6 +33,7 @@ module Habarico
30
33
  reference = generate_reference(action, context)
31
34
  if reference.present?
32
35
  resource_path_2 = ResourceService.instance.get_resource_path(reference)
36
+ raise Eluvia::Errors::StandardError.new("Resource `#{reference}` referenced by action `#{action.name}` is not registered.") if resource_path_2.blank?
33
37
  result += "/#{resource_path_2.join('/')}"
34
38
  else
35
39
  result += "/#{resource_path.join('/')}"
@@ -56,14 +60,16 @@ module Habarico
56
60
  end
57
61
 
58
62
  def generate_action_name(action, _context)
63
+ return action.endpoint_action_name if action.endpoint_action_name.present?
59
64
  return nil if Habarico::ActionHelper.is_standard_action?(action)
60
- action.endpoint_action_name || action.name
65
+ action.name
61
66
  end
62
67
 
63
68
  def generate_record_pk(action, context)
64
- if action&.is_detail
65
- context.record_pk
66
- end
69
+ # An explicit record pk on the action wins over the record in the context: it is how an
70
+ # action targets a record other than the one it was invoked on.
71
+ return action.endpoint_record_pk if action.endpoint_record_pk.present?
72
+ context.record_pk if action&.is_detail
67
73
  end
68
74
 
69
75
  end
@@ -8,7 +8,8 @@ module Habarico
8
8
 
9
9
  # Create model
10
10
  Habarico::SaveActionParameters.new(
11
- data: generate_data(action, context)
11
+ data: generate_data(action, context),
12
+ after_save: generate_after_save(action, context)
12
13
  )
13
14
  end
14
15
 
@@ -22,5 +23,9 @@ module Habarico
22
23
  Habarico::CallableHelper.resolve(action.data, context)
23
24
  end
24
25
 
26
+ def generate_after_save(action, _context)
27
+ action.after_save
28
+ end
29
+
25
30
  end
26
31
  end
@@ -0,0 +1,52 @@
1
+ module Habarico
2
+ # Builds the `Habarico::ActionSchema` of a trigger action - the follow-up action the frontend
3
+ # runs after a custom action's response, or the one attached to a serialized record.
4
+ class TriggerActionSchemaGenerator < AbstractGenerator
5
+
6
+ # `action` is the name of an action declared in `actions`, a `Habarico::Action` or a ready
7
+ # `Habarico::ActionSchema`, which is returned as is. `record_pk` and `reference` retarget the
8
+ # action at another record and another resource.
9
+ def generate(action, context, record_pk: nil, reference: nil)
10
+ return nil if action.nil?
11
+ return action if action.is_a?(Habarico::ActionSchema)
12
+
13
+ action = find_declared_action!(action) if action.is_a?(::String) || action.is_a?(::Symbol)
14
+ unless action.is_a?(Habarico::Action)
15
+ raise Eluvia::Errors::StandardError.new(
16
+ "Trigger action must be a Habarico::ActionSchema, a Habarico::Action or an action name, got `#{action.class}`."
17
+ )
18
+ end
19
+
20
+ action_schema_generator.generate(retarget(action, record_pk, reference), context)
21
+ end
22
+
23
+ protected
24
+
25
+ def action_schema_generator
26
+ @action_schema_generator ||= definition.action_schema_generator.new(definition, resource_path)
27
+ end
28
+
29
+ # Copies the action before setting the target, so a declared action is never mutated.
30
+ def retarget(action, record_pk, reference)
31
+ return action if record_pk.blank? && reference.blank?
32
+
33
+ action = action.dup
34
+ action.endpoint_record_pk = record_pk if record_pk.present?
35
+ action.endpoint_reference = reference if reference.present?
36
+ action
37
+ end
38
+
39
+ # An unknown name raises, since it is far more likely a typo than a deliberately empty trigger.
40
+ def find_declared_action!(name)
41
+ declared = definition.normalized_actions
42
+ action = declared.find { |declared_action| declared_action.name.to_s == name.to_s }
43
+ return action if action
44
+
45
+ raise Eluvia::Errors::StandardError.new(
46
+ "Action `#{name}` is not declared in `actions` of resource `#{resource_path&.last}`. " \
47
+ "Declared actions: #{declared.map(&:name).join(', ').presence || 'none'}."
48
+ )
49
+ end
50
+
51
+ end
52
+ end
@@ -11,7 +11,8 @@ module Habarico
11
11
  reference: generate_reference(action, context),
12
12
  target: generate_target(action, context),
13
13
  accept: generate_accept(action, context),
14
- image_field: generate_image_field(action, context)
14
+ image_field: generate_image_field(action, context),
15
+ data: generate_data(action, context)
15
16
  )
16
17
  end
17
18
 
@@ -37,5 +38,9 @@ module Habarico
37
38
  action.upload_images_image_field
38
39
  end
39
40
 
41
+ def generate_data(action, context)
42
+ Habarico::CallableHelper.resolve(action.upload_images_data, context)
43
+ end
44
+
40
45
  end
41
46
  end
@@ -24,13 +24,18 @@ module Habarico
24
24
  end
25
25
 
26
26
  def generate_action_name(action, _context)
27
- action.endpoint_action_name || action.name
27
+ return action.endpoint_action_name if action.endpoint_action_name.present?
28
+ # A standard action is reached through the resource's standard endpoint, which carries no
29
+ # action name - the frontend derives it from the view alone.
30
+ return nil if Habarico::ActionHelper.is_standard_action?(action)
31
+ action.name
28
32
  end
29
33
 
30
34
  def generate_record_pk(action, context)
31
- if action&.is_detail
32
- context.record_pk
33
- end
35
+ # An explicit record pk on the action wins over the record in the context: it is how an
36
+ # action targets a record other than the one it was invoked on.
37
+ return action.endpoint_record_pk if action.endpoint_record_pk.present?
38
+ context.record_pk if action&.is_detail
34
39
  end
35
40
 
36
41
  end
@@ -12,6 +12,7 @@ module Habarico
12
12
  mode: generate_mode(action, context),
13
13
  dialog_width: generate_dialog_width(action, context),
14
14
  parameters: generate_parameters(action, context),
15
+ choices: generate_choices(action, context),
15
16
  endpoint: generate_endpoint(action, context),
16
17
  keep_linked_parent: generate_keep_linked_parent(action, context)
17
18
  )
@@ -43,8 +44,15 @@ module Habarico
43
44
  Habarico::CallableHelper.resolve(action.view_parameters, context)
44
45
  end
45
46
 
47
+ def generate_choices(action, context)
48
+ Habarico::CallableHelper.resolve(action.view_choices, context)
49
+ end
50
+
46
51
  def generate_endpoint(action, context)
47
- return nil if Habarico::ActionHelper.is_standard_action?(action)
52
+ # A standard action of the current resource needs no endpoint - the frontend opens the view
53
+ # over the record it already has. One that names its own target does: the endpoint is where
54
+ # the target resource and record are written down.
55
+ return nil if Habarico::ActionHelper.is_standard_action?(action) && !Habarico::ActionHelper.has_explicit_target?(action)
48
56
  view_action_endpoint_parameters_generator.generate(action, context)
49
57
  end
50
58
 
@@ -5,5 +5,13 @@ module Habarico
5
5
  %w[show create update delete].include?(action.name)
6
6
  end
7
7
 
8
+ # An action that spells out its own target - another resource, another record, or both. Such an
9
+ # action always needs its endpoint in the schema, even when its name is one of the standard
10
+ # ones: the endpoint is the only place the target is written down, and without it the frontend
11
+ # falls back to the resource and the record the action ran on.
12
+ def self.has_explicit_target?(action)
13
+ action.endpoint_reference.present? || action.endpoint_record_pk.present?
14
+ end
15
+
8
16
  end
9
17
  end
@@ -2,9 +2,15 @@ module Habarico
2
2
  class SaveActionParameters
3
3
  include ::ActiveModel::Model
4
4
  include Eluvia::ActiveModel::Attributes
5
+ include Eluvia::ActiveModel::EnumAttribute
5
6
 
6
7
  # Data that will be added to the object before saving
7
8
  any_attr :data
8
9
 
10
+ # Where the form goes once the record is saved. When not set, the frontend keeps its own
11
+ # default behaviour.
12
+ string_attr :after_save
13
+ enum_attr :after_save, Types::AFTER_SAVE_TYPE
14
+
9
15
  end
10
16
  end
@@ -19,5 +19,8 @@ module Habarico
19
19
  # frontend to know which attribute to set on the record it creates for each upload.
20
20
  string_attr :image_field
21
21
 
22
+ # Additional data added to every image record the frontend creates for an upload
23
+ any_attr :data
24
+
22
25
  end
23
26
  end
@@ -20,6 +20,9 @@ module Habarico
20
20
  # Additional parameters to be passed to the view
21
21
  has_many_attr :parameters, 'String', underlying_type: :hash
22
22
 
23
+ # Choices offered before the view opens, each carrying its own view parameters
24
+ has_many_attr :choices, 'Habarico::ActionViewChoice'
25
+
23
26
  # Keep linked parent in the URL when navigating to the linked resource
24
27
  boolean_attr :keep_linked_parent
25
28
 
@@ -52,6 +52,9 @@ module Habarico
52
52
  # LinkTargetType - where a link action opens
53
53
  LINK_TARGET_TYPE = %i[self blank].freeze
54
54
 
55
+ # AfterSaveType - where a save action goes once the record is saved
56
+ AFTER_SAVE_TYPE = %i[stay prev show list].freeze
57
+
55
58
  # TextAlignType - horizontal alignment of a field value
56
59
  TEXT_ALIGN_TYPE = %i[left center right].freeze
57
60
 
data/lib/habarico.rb CHANGED
@@ -133,6 +133,7 @@ require "habarico/generators/action/global_resource_action_schema_generator"
133
133
  require "habarico/generators/action/resource_action_schema_generator"
134
134
  require "habarico/generators/action/save_action_parameters_generator"
135
135
  require "habarico/generators/action/upload_images_action_parameters_generator"
136
+ require "habarico/generators/action/trigger_action_schema_generator"
136
137
 
137
138
  # Endpoint generators
138
139
  require "habarico/generators/endpoint/method_schema_generator"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: habarico
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.3.0.pre.beta.2
4
+ version: 7.3.0.pre.beta.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matěj Outlý
@@ -177,6 +177,7 @@ files:
177
177
  - lib/habarico/generators/action/resource_action_parameters_generator.rb
178
178
  - lib/habarico/generators/action/resource_action_schema_generator.rb
179
179
  - lib/habarico/generators/action/save_action_parameters_generator.rb
180
+ - lib/habarico/generators/action/trigger_action_schema_generator.rb
180
181
  - lib/habarico/generators/action/upload_images_action_parameters_generator.rb
181
182
  - lib/habarico/generators/action/view_action_endpoint_parameters_generator.rb
182
183
  - lib/habarico/generators/action/view_action_parameters_generator.rb