easy_flow 0.37.0 → 0.38.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 738d119d2cab4783784532361d52c24c2b2825066ad8970a4dfa03e8e0e3c405
4
- data.tar.gz: fc233a4ea07c339f27f62f87b83ad218e771ee19bcee08a1e795cde7d1f18c10
3
+ metadata.gz: f6e3917c026a19b26bda2e359502b982a224acb117fa83a73bbed2c8c50be70e
4
+ data.tar.gz: bfb5803080cb0ce7b91734d1ca3798b010fa5e5d55fa1502a449e6c7ca7811a0
5
5
  SHA512:
6
- metadata.gz: 95b62e84987cf90ef6eb7061165cb3a733c0a658c91901d46920bb48fcd6364d9642571b9069be6983e9c5983eaa6a97e3c98c174d34a97f83c9e20182d3b915
7
- data.tar.gz: a83ed3214d6b9c161b3eaeac4d72f3552ac847f2d4bf7ca30685a3dc0861a299c96b52625398cd582a20d1c0e791e0ff7d30e0f33f83d2e08eb3630f42173169
6
+ metadata.gz: b9b2f93f31c3c1dbf35a238acda8f614b6655ebcf62f60a26a72f55eed87054551f4e76a2943b6d3959cea4e8fbed927fefbebd47f683193aa26e353c1cf047a
7
+ data.tar.gz: a66b7d38f6f02c1aef0e2cc02232bdbc4ed948f822992fc4a6db63cd5560ab49357829b337c4bb5dd22b0a8ec7213aa76066d96d6cdbc2da381e6e925817cdaf
@@ -101,11 +101,12 @@ module EasyFlow
101
101
  end
102
102
 
103
103
  def palette_entry(step_type)
104
+ hidden = hidden_settings_of(step_type)
104
105
  { "type" => step_type.id.to_s, "label" => step_type.step_name,
105
- "fields" => step_type.settings.fields.transform_keys(&:to_s).transform_values(&:to_s),
106
- "labels" => step_type.settings.labels.transform_keys(&:to_s),
107
- "explanations" => explanations_of(step_type),
108
- "choices" => step_type.settings.choices.transform_keys(&:to_s),
106
+ "fields" => step_type.settings.fields.except(*hidden).transform_keys(&:to_s).transform_values(&:to_s),
107
+ "labels" => step_type.settings.labels.except(*hidden).transform_keys(&:to_s),
108
+ "explanations" => explanations_of(step_type).except(*hidden.map(&:to_s)),
109
+ "choices" => step_type.settings.choices.except(*hidden).transform_keys(&:to_s),
109
110
  "records" => holdings_of(step_type),
110
111
  "record_choices" => step_type.settings.record_choices.to_h { |name, offered| [ name.to_s, offered.transform_keys(&:to_s) ] },
111
112
  "record_outputs_of" => step_type.settings.record_outputs_of.to_h { |name, sources| [ name.to_s, sources.to_h { |field, source| [ field.to_s, source.to_s ] } ] },
@@ -114,6 +115,10 @@ module EasyFlow
114
115
  "awaits_input" => step_type.awaits_input? }
115
116
  end
116
117
 
118
+ def hidden_settings_of(step_type)
119
+ step_type.id == :terminal && !@host&.marks_ends? ? [ :mark ] : []
120
+ end
121
+
117
122
  def explanations_of(step_type)
118
123
  settings = step_type.settings
119
124
  settings.fields.keys.to_h { |name| [ name.to_s, @host&.explanation_for(step_type.id, name) || settings.explanations[name] ] }.compact
@@ -77,10 +77,11 @@ module EasyFlow
77
77
  end
78
78
 
79
79
  def output(state, times = {})
80
- ended = nil
81
- walk(state, times) { |cursor| ended = cursor }
80
+ ended_setting(state, times, "output")
81
+ end
82
82
 
83
- ended.config["output"].presence if step_type(ended)&.ends_here?
83
+ def end_mark(state, times = {})
84
+ ended_setting(state, times, "mark")
84
85
  end
85
86
 
86
87
  def ended_at_end?(state, times = {})
@@ -112,6 +113,13 @@ module EasyFlow
112
113
 
113
114
  private
114
115
 
116
+ def ended_setting(state, times, name)
117
+ ended = nil
118
+ walk(state, times) { |cursor| ended = cursor }
119
+
120
+ ended.config[name].presence if step_type(ended)&.ends_here?
121
+ end
122
+
115
123
  def walk(state, times = {})
116
124
  recorded = []
117
125
  latest = {}
@@ -52,6 +52,10 @@ module EasyFlow
52
52
  digest.output(recorded.transform_keys(&:to_s), completed_at.transform_keys(&:to_s))
53
53
  end
54
54
 
55
+ def end_mark
56
+ digest.end_mark(recorded.transform_keys(&:to_s), completed_at.transform_keys(&:to_s))
57
+ end
58
+
55
59
  def held_until
56
60
  stopped_at = next_step(recorded)
57
61
  Wait.held_until(digest.step(stopped_at.id), CompletedAt.latest(completed_at)) if stopped_at&.type == "wait"
@@ -8,6 +8,8 @@ module EasyFlow
8
8
 
9
9
  setting :output, type: :string
10
10
 
11
+ setting :mark, type: :select, options: %w[success failure]
12
+
11
13
  names_by { |_node| "End" }
12
14
  end
13
15
  end
@@ -235,7 +235,11 @@ module EasyFlow
235
235
  def required_of(node)
236
236
  return [] unless @registry.registered?(node.type)
237
237
 
238
- @registry.fetch(node.type).settings.required
238
+ @registry.fetch(node.type).settings.required + marks_required_of(node)
239
+ end
240
+
241
+ def marks_required_of(node)
242
+ node.type == "terminal" && @flow && EasyFlow.host_named(@flow.host).marks_ends? ? [ :mark ] : []
239
243
  end
240
244
 
241
245
  def requirements_for(node)
@@ -3,7 +3,7 @@ module EasyFlow
3
3
  BackLink = Data.define(:label, :address)
4
4
 
5
5
  attr_reader :name, :back_link
6
- attr_writer :layout, :admin_layout, :offers, :allowed_answers, :always_show_insert_buttons, :hide_step_type_codes
6
+ attr_writer :layout, :admin_layout, :offers, :allowed_answers, :always_show_insert_buttons, :hide_step_type_codes, :marks_ends
7
7
  attr_accessor :admin_authentication_method, :visitor_authorization_method, :refusal_method, :owner_method, :finds_flows_across_owners, :publish_note
8
8
 
9
9
  def initialize(name)
@@ -45,6 +45,10 @@ module EasyFlow
45
45
  @always_show_insert_buttons.present?
46
46
  end
47
47
 
48
+ def marks_ends?
49
+ @marks_ends.present?
50
+ end
51
+
48
52
  def hide_step_type_codes?
49
53
  @hide_step_type_codes.present?
50
54
  end
@@ -1,3 +1,3 @@
1
1
  module EasyFlow
2
- VERSION = "0.37.0"
2
+ VERSION = "0.38.0"
3
3
  end
@@ -24,7 +24,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
24
24
  - `routed_by` — class method on a `FlowsController` subclass naming the prefix of the app's own route names that the controller redirects and links to.
25
25
  - `run_address` — private method a `FlowsController` subclass overrides to give the value put in a run's address in place of its id.
26
26
  - `find_run` — private method a `FlowsController` subclass overrides to find a run, among the host's own runs, from the value in its address.
27
- - `EasyFlow::Run` — the stored record of one visitor's pass through a flow, started with `EasyFlow::Run.start` on the live version or a chosen published one and pinned to that version, moved on past a waiting step with `advance`, read for the output its flow ended with by `output`, for whether it ended at an End step by `ended_at_end?`, for the step a loop stopped it at by `stopped_on_loop`, for when each step visit was completed by `completed_at` and for the time a Wait step holds it until by `held_until`, and linked to the runs its Flow steps started by `inner_runs`, to the one it is waiting on by `waiting_on`, and to the run that started it by `parent_run`.
27
+ - `EasyFlow::Run` — the stored record of one visitor's pass through a flow, started with `EasyFlow::Run.start` on the live version or a chosen published one and pinned to that version, moved on past a waiting step with `advance`, read for the output its flow ended with by `output`, for the mark of the End it reached by `end_mark`, for whether it ended at an End step by `ended_at_end?`, for the step a loop stopped it at by `stopped_on_loop`, for when each step visit was completed by `completed_at` and for the time a Wait step holds it until by `held_until`, and linked to the runs its Flow steps started by `inner_runs`, to the one it is waiting on by `waiting_on`, and to the run that started it by `parent_run`.
28
28
  - `EasyFlow::QuestionRunner` — reads a flow document: its steps, the next step for a set of answers and the times their steps were completed, the answers on the path taken, and a question's text and an answer's label.
29
29
 
30
30
  ## How to use it
@@ -541,6 +541,7 @@ Use this when a visitor's run should stop until a set time has passed, such as a
541
541
  - `run.pinned_definition` — the flow document of the version the run started on.
542
542
  - `run.next_step(answers)` and `run.walked(answers)` — the next step, and the answers on the path taken, for a set of answers against that pinned version, routed with the run's own `completed_at`.
543
543
  - `run.output` — the text the admin wrote into the output setting of the End step the run ended on, read from the run's pinned version. It is `nil` when the run has not reached an End step, or ended on one whose output was left blank. A flow may have several End steps with a different output on each, so the output says which way the flow ended. Ask the developer what the app does with each output, and what it does when there is none.
544
+ - `run.end_mark` — `"success"` or `"failure"`, the mark an admin gave the End step the run ended on, read from the run's pinned version, in a host that sets `marks_ends`. It is `nil` when the run has not reached an End step, or reached one left unmarked, such as one on a version published before the host asked for marks. Ask the developer what the app does with a run whose End has no mark.
544
545
  - `run.ended_at_end?` — `true` when the run is not stopped at a step that awaits input, computes a value or waits, and the last step it reached is of a type that declares `ends_here`, such as the built-in End step, whether or not that step has an output. It is `false` while the run is still going, including while it waits at a Flow step, when a loop stopped it, and when it ended at a step that is not an end, such as a step with no connection leaving it or a `route` value that matches no connection's label. Use it to tell a run that ended at an End step with a blank output from one that stopped anywhere else, since `run.output` is `nil` for both.
545
546
  - `run.stopped_on_loop` — the id of the step a loop came back to when it stopped the run, as a string, the plain step id and never a visit key such as `"tally@2"`, or `nil` when no loop stopped it. A loop stops the run when it comes back to a step already visited with no step that awaits input answered since that step's last visit, such as a loop of Count steps only. The run ends there, and `run.ended_at_end?` is `false`. When a Flow step started the run, nothing is handed to its parent run, which stays waiting at that step; see step 5 of "Follow a run into the flow a Flow step started". Ask the developer what the app does with a run a loop stopped, such as showing an admin the step named. Do not pick.
546
547
  - `run.advance` — moves the run past every waiting step whose `waits_until` block now returns a truthy value, and past every step that computes a value, and records each result on the run. It stops at the next step that asks the visitor for input, the next waiting step that is not ready, or the end. It does not call `finished`; that is called the next time the visitor loads the run's page. When it stops at a Flow step it starts that step's run, and when it reaches the end of a run a Flow step started it hands the output to the parent run, unless a loop stopped the run; see "Follow a run into the flow a Flow step started".
@@ -58,7 +58,8 @@ easy_flow declares no commands of its own for this local. Its surface is split b
58
58
  - **Kept setting** — a setting whose value lives on one of the app's own records rather than in the flow. The step type says how to find that record from the step's other settings and which of its attributes holds the value. The canvas shows the value read from the record, and saving the step's settings writes it straight to the record, so the flow's document and its versions never hold it and undo or publishing does not change it. When no record is found, nothing is written. When the record refuses a value, the save is refused with the record's own error and none of the step's kept settings are written.
59
59
  - **Output** — a value a step records into the run, with a type and a label. Later steps read outputs, and a setting that points at an earlier step offers that step's known values on the canvas. A step type may also take further outputs from a list setting, one for each entry the admin gives a name, labelled with that name written as a phrase, such as "First reading" for `first_reading`. An entry left without a name adds no output. Those outputs are offered wherever the step's declared outputs are, such as when a Condition, Compare, Compare two values, All of or Any of or Count step picks which output to read.
60
60
  - **Chosen output** — which of an earlier step's outputs a step reads. Every built-in step that names an earlier step and then reads one of its outputs asks the admin to pick that output, as does a step type of the app's own whose output setting points at a step setting. Once the earlier step is named, a step with no output picked is reported as missing that setting, and the same holds for each comparison in an All of or Any of list, for its first step and for its second step. A step that names no earlier step, such as a Compare two values step with its second step left empty, is not asked for that step's output.
61
- - **Start** and **End** — the built-in step types that begin and finish a flow. An End step has one setting, its output.
61
+ - **Start** and **End** — the built-in step types that begin and finish a flow. An End step has one setting, its output, and a second, its mark, in a host that sets `marks_ends`.
62
+ - **End mark** — success or failure, chosen by an admin on each End step of a host that sets `marks_ends`, so a run that ended says whether it ended well. Publishing such a flow with an End left unmarked is refused. A stored run gives the mark of the End it reached, and gives none when it has not reached one or reached one left unmarked.
62
63
  - **Flow output** — the text an admin writes into the output setting of an End step, given as the result of a stored run that has reached that step. A flow may hold several End steps with a different output on each, so the output says which way the flow ended. A run that has not reached an End step, or that ended on one whose output was left blank, gives no output.
63
64
  - **Question** — the built-in step type that asks the visitor: a question text, an optional category, a yes-or-no required setting, and a list of answers, each with a value, a label, a weight, a hint and an info. The visitor picks one answer, and that answer's value is recorded.
64
65
  - **Checklist** — the built-in step type that asks the visitor to tick any number of answers: a question text, a yes-or-no required setting, and a list of answers, each with a value, a label and an info. The list of ticked values is recorded, and a checklist left with nothing ticked records an empty list.
@@ -60,6 +60,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
60
60
  - `offers` — the step types this host's admins can add from the canvas palette, as a list of step type names. With none set, every registered step type is offered. The engine's own names are `question`, `checklist`, `multiple_select`, `fill_in_the_blank`, `file_upload`, `condition`, `switch`, `compare`, `compare_two_values`, `all_or_any`, `count`, `wait`, `flow_step` and `play_flows`, `file_upload` being the File upload step, which needs the file store from step 10, `compare_two_values` being the Compare two values step, which compares the outputs of two earlier steps, `all_or_any` being the All of or Any of step, which decides whether all or any of several such comparisons hold, `count` being the Count step, which counts how often an earlier step was answered, `wait` being the Wait step, which holds a run until a time counted from an earlier answer or until a date, `flow_step` being the Flow step, which names one of the same host's flows, and `play_flows` being the Play flows step, which lists several of the same host's flows for a visitor to play in the order they choose. A step type the app declares is named by the id it was declared with, or after its class when it is a step class, so `Steps::Notify` is `notify`. The End step is offered whether it is listed or not, and the Start step is never offered. Ask the developer which step types each host should offer.
61
61
  - `always_show_insert_buttons` — set to `true` to show each connection's button for inserting a step on this host's canvas without the pointer over the connection. A connection's label then sits to the right of the line so the button does not cover it. With none set, the button shows only with the pointer over the connection.
62
62
  - `hide_step_type_codes` — set to `true` to hide step type code names on this host's canvas. The add menu then lists each step type by its name alone, and a step's box shows its step type's name in place of the code name. With none set, the add menu and step boxes show the code names. The settings panel shows a step's id and code name either way.
63
+ - `marks_ends` — set to `true` to have this host's admins mark each End step as success or failure. The End step's settings then show a Mark with those two choices, and publishing one of this host's flows with an End left unmarked is refused, the refusal shown on that End's card. With none set, End steps show no mark and publish as they do. Ask the developer whether this host's runs need to say if they ended well.
63
64
  - `publish_note` — a sentence shown directly under the Publish button in this host's flow panel. It is shown as plain text. With none set, the panel shows no note.
64
65
  - `back_link` — a hash with a `label` and an `address`, such as `{ label: "Games", address: "/admin/games" }`, that shows a button with that label and address in this host's builder header in place of `All flows`. The header then has no `All flows` button. A hash missing either key raises `ArgumentError` when the host is declared, and a blank value is not refused. The address is used as written and is not checked, so it comes from the app's own configuration and never from a request. With none set, the header shows `All flows`.
65
66
  - `setting_explanations` — this host's own explanations for step type settings, as a hash of step type name to setting name to a sentence, such as `{ multiple_select: { category: "The round this question counts toward.", "answers.weight" => "Points this answer adds to the score." } }`. A setting inside a list is named by the list and the setting joined with a dot, and a list setting's own explanation is named by the list alone. The sentence is shown as plain text under the setting in the step's settings, in place of the step type's own. A setting with none, or with a blank one, shows the step type's own, if it has one. A step type or setting name that matches nothing is ignored. A value that is not text, such as a nested hash, raises `ArgumentError` when the host is declared. With none set, every setting shows the step type's own explanation.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_flow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.37.0
4
+ version: 0.38.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tylercschneider