easy_flow 0.11.0 → 0.12.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: 62d908e1b9ce4b3b8845a80302af79e28801fa9ec737cf3b09c0032f123d6137
4
- data.tar.gz: 5118f5f7f8a333facae18c4a61e725cdc099d1e97e69c0c26e0065aa427e621b
3
+ metadata.gz: cd76ff73b7535488466a0d9b117baa070987f3cefae1947d0b6b038a794408d0
4
+ data.tar.gz: 8193d30d3f11a20720c01d25d23e1666406d674f57da2e2dbfc0387a4c0c94be
5
5
  SHA512:
6
- metadata.gz: 6cd630296d7d273e0992399e0678dcc655872f95cd7555bb8064f2bb37bf516e2dfcdddbe114551601dc085a0d3c97499f71a20ee1a7b7e993adc1d0aa3c4596
7
- data.tar.gz: e796ff7990e86671ef6c49f17ee36b45c97fc064c9efdf335c07dfa2e1b63a8c07ee126d41881636171a019c5f77a1213069a1ccef310783331ed14ed19f4bdf
6
+ metadata.gz: ae11c115249f725fd651f83341861470d0885cc2171da51742c9eb5e79215e23bdc86a4fb3ac02bfea83f0c942182050c3f4d6cb66e9711a674f2a4c47249602
7
+ data.tar.gz: 619f909b5d2054f382145510315e0f55a5843b220c92a13f51bf9a19b7d39766a8aaa25985b15c17f19577b8cf252a9cf2f20eafefa02ffbefc15df9756984ec
@@ -1,9 +1,20 @@
1
1
  module EasyFlow
2
2
  ChosenFlow = Data.define(:flow_id, :number) do
3
- def self.of(node)
3
+ def self.of(node, registry: EasyFlow.registry)
4
+ chosen = (registry.fetch(node.type).flow_chosen_by(node) if registry.registered?(node.type))
5
+ return worked_out(chosen) if chosen
6
+
4
7
  new(flow_id: node.config["flow"].presence, number: node.config["version"].presence)
5
8
  end
6
9
 
10
+ def self.worked_out(chosen)
11
+ new(flow_id: chosen[:flow].presence, number: chosen[:version].presence)
12
+ end
13
+
14
+ def name
15
+ [ flow&.title, ("version #{number}" if number) ].compact.join(", ").presence
16
+ end
17
+
7
18
  def flow
8
19
  Definition.find_by(id: flow_id) if flow_id
9
20
  end
@@ -13,10 +13,7 @@ module EasyFlow
13
13
 
14
14
  waits_until { |_node, _state| false }
15
15
 
16
- names_by do |node|
17
- chosen = ChosenFlow.of(node)
18
- [ chosen.flow&.title, ("version #{chosen.number}" if chosen.number) ].compact.join(", ").presence
19
- end
16
+ names_by { |node| ChosenFlow.of(node).name }
20
17
 
21
18
  def self.endings_of(node)
22
19
  version = ChosenFlow.of(node).version
@@ -70,6 +70,10 @@ module EasyFlow
70
70
  @starts_a_flow = true
71
71
  end
72
72
 
73
+ def chooses_flow(&chooser)
74
+ @flow_chooser = chooser
75
+ end
76
+
73
77
  def names_by(field = nil, &naming)
74
78
  @naming_field = field
75
79
  @naming = naming
@@ -116,7 +120,7 @@ module EasyFlow
116
120
 
117
121
  def to_step_type
118
122
  StepType.new(id: @id, step_name: @step_name, settings: settings, awaits_input: @awaits_input,
119
- ends_here: @ends_here, begins_here: @begins_here, starts_a_flow: @starts_a_flow, behaviour: @behaviour, routing: @routing,
123
+ ends_here: @ends_here, begins_here: @begins_here, starts_a_flow: @starts_a_flow, flow_chooser: @flow_chooser, behaviour: @behaviour, routing: @routing,
120
124
  display: @display, drawn_by: @drawn_by, naming_field: @naming_field, naming: @naming,
121
125
  outputs: @declared_outputs, answer_check: @answer_check, readiness: @readiness)
122
126
  end
@@ -7,7 +7,7 @@ module EasyFlow
7
7
  attr_reader :id, :step_name, :settings, :naming_field, :naming, :outputs, :drawn_by
8
8
 
9
9
  def initialize(id:, step_name:, settings:, awaits_input:, behaviour:, routing:,
10
- ends_here: false, begins_here: false, starts_a_flow: false, display: nil, drawn_by: nil,
10
+ ends_here: false, begins_here: false, starts_a_flow: false, flow_chooser: nil, display: nil, drawn_by: nil,
11
11
  naming_field: nil, naming: nil, outputs: [], answer_check: nil, readiness: nil)
12
12
  @id = id
13
13
  @step_name = step_name
@@ -16,6 +16,7 @@ module EasyFlow
16
16
  @ends_here = ends_here
17
17
  @begins_here = begins_here
18
18
  @starts_a_flow = starts_a_flow
19
+ @flow_chooser = flow_chooser
19
20
  @behaviour = behaviour
20
21
  @routing = routing
21
22
  @display = display
@@ -54,7 +55,7 @@ module EasyFlow
54
55
  end
55
56
 
56
57
  def name_of(node)
57
- @naming&.call(node).presence || node.config[naming_field.to_s].presence
58
+ @naming&.call(node).presence || node.config[naming_field.to_s].presence || worked_out_flow_name(node)
58
59
  end
59
60
 
60
61
  def acts?
@@ -84,5 +85,14 @@ module EasyFlow
84
85
  def starts_a_flow?
85
86
  @starts_a_flow
86
87
  end
88
+
89
+ def flow_chosen_by(node)
90
+ @flow_chooser&.call(node)
91
+ end
92
+
93
+ def worked_out_flow_name(node)
94
+ chosen = flow_chosen_by(node)
95
+ ChosenFlow.worked_out(chosen).name if chosen
96
+ end
87
97
  end
88
98
  end
@@ -1,3 +1,3 @@
1
1
  module EasyFlow
2
- VERSION = "0.11.0"
2
+ VERSION = "0.12.0"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: easy_flow-develop
3
- description: Use PROACTIVELY for adding a step type to easy_flow flows (a step that asks the visitor something, takes several answers at once, computes a value from earlier answers, picks the next branch, or holds the visitor until something outside the flow has happened), showing a step differently depending on the visitor's stored run, branching on what a visitor ticked on a checklist, moving a paused run on once what it waits for has happened, refusing a blank or invalid answer to a step with a message, offering an admin a step setting whose options are read from the app's own records, letting an admin pick another flow of the same host in a step's settings, letting an admin edit a value stored on one of the app's own records from a step's settings on the canvas, serving a host's flows from the app's own controller and routes, starting a visitor's run on a published version of a flow other than the live one, acting when a visitor finishes a flow, acting on the output a visitor's flow ended with, keeping a flow from being published while a step that starts another flow names a flow or version that cannot run or leads back to the flow it sits in, finding the run of another flow that a Flow step started, the run a waiting run is waiting on, and the run that started it, sending a visitor back to the run that started a flow once that flow ends, handling a run whose starting run was removed with its flow, handling a Flow step that cannot start its flow or whose flow ended with no output, and reading a run's recorded answers and question labels, including every answer ticked on a checklist and every visit's answer when a flow loops back to a question already asked — MUST BE USED instead of hand-rolling questionnaire steps, checkbox lists, branching logic, number comparisons, hard-coded setting options, copying a record's value into a flow and back, answer validation, polling or "come back later" pages, flow controllers or answer lookups.
3
+ description: Use PROACTIVELY for adding a step type to easy_flow flows (a step that asks the visitor something, takes several answers at once, computes a value from earlier answers, picks the next branch, or holds the visitor until something outside the flow has happened), showing a step differently depending on the visitor's stored run, branching on what a visitor ticked on a checklist, moving a paused run on once what it waits for has happened, refusing a blank or invalid answer to a step with a message, offering an admin a step setting whose options are read from the app's own records, letting an admin pick another flow of the same host in a step's settings, adding a step type that starts another flow and works out which flow and version to run from its own settings, letting an admin edit a value stored on one of the app's own records from a step's settings on the canvas, serving a host's flows from the app's own controller and routes, starting a visitor's run on a published version of a flow other than the live one, acting when a visitor finishes a flow, acting on the output a visitor's flow ended with, keeping a flow from being published while a step that starts another flow names a flow or version that cannot run or leads back to the flow it sits in, finding the run of another flow that a Flow step started, the run a waiting run is waiting on, and the run that started it, sending a visitor back to the run that started a flow once that flow ends, handling a run whose starting run was removed with its flow, handling a Flow step that cannot start its flow or whose flow ended with no output, and reading a run's recorded answers and question labels, including every answer ticked on a checklist and every visit's answer when a flow loops back to a question already asked — MUST BE USED instead of hand-rolling questionnaire steps, checkbox lists, branching logic, number comparisons, hard-coded setting options, copying a record's value into a flow and back, answer validation, polling or "come back later" pages, flow controllers or answer lookups.
4
4
  tools: Read, Write, Edit, Grep
5
5
  scope: guided flows — versioned documents of steps and the connections between them, drawn on a canvas by an admin and run by a visitor one step at a time, with step types the host registers
6
6
  ---
@@ -83,7 +83,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
83
83
  - `waits_until { |node, state| ... }` — the run stops at this step until the block returns a truthy value. See step 8.
84
84
  - `answer_check { |node, value| ... }` — checks a submitted answer before it is recorded. `value` is the submitted string, an array of strings when the input submits several values, or `nil` or `""` when the input sent nothing. An array may hold blank strings. Return a message to refuse the answer, or `nil` to accept it. Without it every answer is accepted, including a blank one.
85
85
  - `ends_here` / `begins_here` — marks the type as an end or a start of a flow. A run that ends on a step of an `ends_here` type gives that step's `output` setting as `run.output`, so a type of the app's own that ends a flow declares `setting :output, type: :string` for the admin to fill in, or gives no output.
86
- - `starts_a_flow` — when a stored run stops at a step of this type, a run of another flow is started. The type must declare `setting :flow, type: :flow` and `setting :version, type: :integer`, since the new run is started on that flow's version with that number. The new run is only started at a step the run stops at, so the type must also declare `waits_until` or `awaits_input`. When the new run ends, its output is recorded under this step's id, so a type that should follow a connection per output defines `route` returning `state[node.id]` and declares an `output` whose `values:` are the outputs the named flow can end with. Before writing such a type, ask the developer whether the built-in Flow step is enough. See "Follow a run into the flow a Flow step started".
86
+ - `starts_a_flow` — when a stored run stops at a step of this type, a run of another flow is started. Without `chooses_flow`, the type must declare `setting :flow, type: :flow` and `setting :version, type: :integer`, since the new run is started on that flow's version with that number. The new run is only started at a step the run stops at, so the type must also declare `waits_until` or `awaits_input`. When the new run ends, its output is recorded under this step's id, so a type that should follow a connection per output defines `route` returning `state[node.id]` and declares an `output` whose `values:` are the outputs the named flow can end with. Before writing such a type, ask the developer whether the built-in Flow step is enough. See "Follow a run into the flow a Flow step started".
87
87
  - On the canvas, a step of the type is marked `Runs a flow`.
88
88
  - Once the step's `flow` setting names a flow, clicking the step takes the admin to that flow's page, and a `Settings` button on the step opens the step's own settings. Any other `:flow` setting the type declares is not followed by the click and is not read when the run is started.
89
89
  - A flow's page reached by clicking the step shows a `Back to <title>` button, or `Back to <slug>` when the flow it came from has no title, which returns the admin to the flow the step is in. The button is shown only when that flow belongs to the same host.
@@ -92,6 +92,37 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
92
92
  - The step's card shows `missing flow` while its `flow` setting is blank or names no existing flow, and `unrunnable version` while the flow exists but its `version` setting is blank, names no version of that flow, or names one that is a draft, retired or withdrawn.
93
93
  - The step's card shows `circular` while its `flow` setting names the flow the step sits in, or names a flow whose chosen version holds a `starts_a_flow` step that leads back to it the same way, through any number of flows. Each flow along the way is read at the version named in the `version` setting of the step that leads to it.
94
94
  - While `missing flow`, `unrunnable version` or `circular` shows, saving the flow as a new version and publishing it are refused. These checks are always made and are not among the optional checks set through `easy_flow-install`, so the type needs no `required:` or `check:` on those two settings for them.
95
+ - `chooses_flow { |node| { flow: ..., version: ... } }` — for a `starts_a_flow` type, works out the flow and version a step runs from the step's own settings instead of reading the settings named `flow` and `version`. Ask the developer which settings decide the flow and version, and how. Do not pick.
96
+ - The block is given the node only. `node.config` holds the admin's settings with string keys, without any setting declared with `kept_on:`.
97
+ - It returns a hash with the symbol keys `flow:`, the flow's id as an integer or a string, and `version:`, the version's number. A blank value under either key is treated as not chosen.
98
+ - When the block returns `nil`, the step falls back to the settings named `flow` and `version`.
99
+ - What it returns is used everywhere the settings named `flow` and `version` are used otherwise: the run started when a stored run stops at the step, the `missing flow`, `unrunnable version` and `circular` marks and the refusal to save or publish, and the flow's page opened by clicking the step on the canvas.
100
+ - The flow is found by its id alone, not through the host or owner. Ask the developer which flows the block may name, and look the flow up through the host inside the block when it must be limited to one host or owner.
101
+ - A step of a type with no `names_by`, or whose `names_by` gives a blank, is named after the flow and version the block returns, as that flow's title and the version number, such as `Onboarding, version 2`, or `version 2` alone when the flow has no title. That name is shown on the canvas and in `Waiting for <name>.` while a run waits at the step. When the block returns `nil`, the step is not named after the settings named `flow` and `version`, and falls back to its id on the canvas and its `step_name` in the waiting message. Ask the developer whether that name is what admins and visitors should read, and declare `names_by` when it is not.
102
+ - The block is called each time the canvas draws the step, each time the step's name is shown, each time the flow is saved as a version or published, and when a run stops at the step, so it must not be slow and must not change anything.
103
+ - A type that routes on the new run's output declares an `output` whose `values:` are the outputs the chosen flow can end with, or the canvas offers no connections to label.
104
+
105
+ ```ruby
106
+ module FlowSteps
107
+ class Offer
108
+ include EasyFlow::Step
109
+
110
+ step_name "Offer"
111
+
112
+ setting :plan, type: :select, options: %w[basic premium], required: true
113
+
114
+ starts_a_flow
115
+ waits_until { |_node, _state| false }
116
+ chooses_flow { |node| OfferFlow.for_plan(node.config["plan"]) }
117
+
118
+ def route(node, state)
119
+ state[node.id]
120
+ end
121
+ end
122
+ end
123
+ ```
124
+
125
+ Here `OfferFlow.for_plan` is the app's own lookup, returning `{ flow: <id>, version: <number> }` or `nil`.
95
126
  - `displays_by { |node| ... }` or `displays_by { |node, run| ... }` — builds the object handed to the step's partial as the local `step`. Without it the partial receives the node itself. A block that takes two arguments is also given the visitor's stored `EasyFlow::Run`, which is `nil` when the flow keeps no stored run at this point and in an admin's preview, so the block must handle `nil`. The block is also called with a `nil` run once for each step already answered every time a step page is shown, to count progress, so it must not be slow and must not change anything.
96
127
  - `drawn_by "<partial>"` — the partial that draws this type for a visitor. Without it the host's default drawing is used, which draws one answer to pick and expects `step.id`, `step.text` and `step.choices`, each choice answering `value`, `label`, `hint` and `info`, so a type with its own display shape needs its own partial.
97
128
  6. For a type that computes or routes, define instance methods on the class (or `process { |node, state| ... }` / `route { |node, state| ... }` in the block form):
@@ -170,13 +201,13 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
170
201
 
171
202
  - The block is given `node` and `state` only, the same as `process`, and is not given the run or its owner. Ask the developer what the step waits for, and how the block finds it from the step's settings and the answers recorded before it. If it cannot be found from those, stop and ask, since the block has nothing else to read.
172
203
  - The block is called each time the visitor loads the step page, and each time the app calls `run.advance`. Keep it to a single lookup.
173
- - While the block returns a falsy value, the visitor is shown `Waiting for <name>.` and no form, no Next button and no Back button. `<name>` is what `names_by` gives, or the `step_name` when there is none, so give the type a name a visitor can read.
204
+ - While the block returns a falsy value, the visitor is shown `Waiting for <name>.` and no form, no Next button and no Back button. `<name>` is what `names_by` gives, or for a type that declares `chooses_flow` the chosen flow's title and version, or the `step_name` when there is neither, so give the type a name a visitor can read.
174
205
  - Once the block returns a truthy value, `true` is recorded under the step's id, or the value `process` returns when the type also defines `process`, and the run goes on to the next step.
175
206
  - Do not declare `awaits_input` on a type that waits. The waiting message replaces the form, so the input is never shown.
176
207
  - The page does not reload itself. Ask the developer how the run should move on when what it waits for happens:
177
208
  - The visitor reloads the page. This needs nothing more, and works whether or not the flow keeps a stored run.
178
209
  - The app calls `run.advance` where the event is handled, such as a webhook or a job. See "Read a run and its answers". This needs a stored run, so it only applies to a flow the admin set to save each step.
179
- 9. Restart the server, open a flow on the canvas of each host that should offer the type, and check the type is in the palette, its settings show, and a preview walks through it. On a host that names a list of offered step types without the type's id, check the type is not in the palette. For a type that declares `starts_a_flow`, check the step is marked `Runs a flow`, that once a flow is picked in its settings clicking the step goes to that flow's page, that the `Back to` button on that page returns to the flow the step is in, and that its `Settings` button opens its settings. Also check that the step shows `missing flow` while no flow is picked, `unrunnable version` while the version number names no live or replaced version, `circular` while it names the flow it sits in, and that publishing is refused until each is fixed.
210
+ 9. Restart the server, open a flow on the canvas of each host that should offer the type, and check the type is in the palette, its settings show, and a preview walks through it. On a host that names a list of offered step types without the type's id, check the type is not in the palette. For a type that declares `starts_a_flow`, check the step is marked `Runs a flow`, that once a flow is picked in its settings clicking the step goes to that flow's page, that the `Back to` button on that page returns to the flow the step is in, and that its `Settings` button opens its settings. Also check that the step shows `missing flow` while no flow is picked, `unrunnable version` while the version number names no live or replaced version, `circular` while it names the flow it sits in, and that publishing is refused until each is fixed. For a type that declares `chooses_flow`, set the settings the block reads and check that clicking the step goes to the flow the block names, that a type with no `names_by` is named on the canvas by that flow's title and version, and that a run stopping at the step starts a run of that flow on that version.
180
211
 
181
212
  ### Keep a setting on one of the app's records
182
213
 
@@ -261,7 +292,7 @@ Use this when a visitor's run reaches a Flow step and the app must take the visi
261
292
 
262
293
  1. This needs the engine's migrations installed, which `easy_flow-install` does.
263
294
  2. What holds when a stored run stops at a Flow step, whether on the visitor's page load or on `run.advance`:
264
- - A run of the flow named in the step's settings is started on the version with the number in its settings. The flow is found by its id alone and not through the host, since a `:flow` setting is not checked on save.
295
+ - A run of the flow named in the step's settings is started on the version with the number in its settings, or of the flow and version its type's `chooses_flow` block returns. The flow is found by its id alone and not through the host, since a `:flow` setting is not checked on save.
265
296
  - The new run's `parent_run` is the run that reached the step, and its `parent_step` is the step's id as a string, or the visit key such as `"sub@2"` on a later visit in a loop.
266
297
  - The new run is moved on at once past every step that acts without the visitor, the same as `run.advance`. When it stops at a Flow step of its own, that starts a further run the same way.
267
298
  - It is started once per visit to the step, so loading the page again or calling `advance` again starts no second one.
@@ -355,7 +386,9 @@ Use this when a visitor's run reaches a Flow step and the app must take the visi
355
386
  - A setting declared with `kept_on:` lives only on the app's record, written when the admin saves the step, so a step's code never finds it in `node.config`.
356
387
  - A `kept_on:` lambda is given only the step's settings, so it cannot limit which records an admin reaches by admin, account or host.
357
388
  - A `:flow` setting holds a flow's id as a string and is not checked against the flows offered, so code reading it looks the flow up through the host.
358
- - A `starts_a_flow` type reads the flow and version to run from the settings named `flow` and `version` and no others.
389
+ - A `starts_a_flow` type reads the flow and version to run from the settings named `flow` and `version`, unless it declares `chooses_flow` and that block returns a choice.
390
+ - A `chooses_flow` block is given only the step, finds the flow by id with no host or owner scope, and is called on every canvas draw, name shown, save and publish, so it limits the flows it names itself and changes nothing.
391
+ - A step of a `chooses_flow` type with no `names_by` is named by the chosen flow's title and version number.
359
392
  - A flow holding a `starts_a_flow` step whose `flow` names no existing flow, or whose `version` names no live or replaced version of it, or whose `flow` leads back to the flow the step sits in directly or through other flows, cannot be saved as a version or published, and these checks cannot be turned off.
360
393
  - On the canvas, clicking a step of a `starts_a_flow` type whose `flow` setting names a flow goes to that flow's page, which has a `Back to` button to the flow the step is in, and the step's settings open from its `Settings` button.
361
394
  - A type that routes declares the values its output takes, or the canvas offers no connections to label.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: easy_flow-info
3
- description: Use to learn what easy_flow offers — guided flows an admin draws on a canvas and a visitor runs one step at a time, versioned documents of steps and connections, flows that loop back to ask a step again, hosts and the step types each offers its admins, runs and the published version each starts on, and the output a flow gives when it ends, the built-in step types including questions and checklists that can require an answer and explain each answer behind an info button, and branching on an answer or comparing a number, Flow steps that name another flow, open its canvas when their card is clicked with a button back to the flow it was opened from, start a run of it for the same owner when a stored run reaches them, are flagged when the flow or version they name cannot run or leads back to the flow they sit in, let the waiting run name that inner run, move that run on along the output it ends with, and fail with an error naming the step when its version was taken out of service or its inner run ended with no output, removing a flow and why it is refused while a waiting run depends on it, step types the host app registers, the checks they make on an answer, what a step shows a visitor and how that can depend on the visitor's run, and steps that hold a run until something outside the flow has happened, and the settings an admin fills in, including picks whose options come from the app's data and settings kept on one of the app's own records.
3
+ description: Use to learn what easy_flow offers — guided flows an admin draws on a canvas and a visitor runs one step at a time, versioned documents of steps and connections, flows that loop back to ask a step again, hosts and the step types each offers its admins, runs and the published version each starts on, and the output a flow gives when it ends, the built-in step types including questions and checklists that can require an answer and explain each answer behind an info button, and branching on an answer or comparing a number, Flow steps that name another flow, open its canvas when their card is clicked with a button back to the flow it was opened from, start a run of it for the same owner when a stored run reaches them, are flagged when the flow or version they name cannot run or leads back to the flow they sit in, let the waiting run name that inner run, move that run on along the output it ends with, and fail with an error naming the step when its version was taken out of service or its inner run ended with no output, removing a flow and why it is refused while a waiting run depends on it, step types the host app registers, including ones that start another flow and work out which flow and version to run from their own settings and are named after that flow, the checks they make on an answer, what a step shows a visitor and how that can depend on the visitor's run, and steps that hold a run until something outside the flow has happened, and the settings an admin fills in, including picks whose options come from the app's data and settings kept on one of the app's own records.
4
4
  tools: Read
5
5
  scope: guided flows — versioned documents of steps and the connections between them, drawn on a canvas by an admin and run by a visitor one step at a time, with step types the host registers
6
6
  ---
@@ -18,12 +18,12 @@ Reach for it when an app needs a questionnaire, an intake form, or any decision
18
18
  easy_flow declares no commands of its own for this local. Its surface is split between the other two:
19
19
 
20
20
  - **easy_flow-install** owns putting the engine into an app: its migrations, mounting it, choosing the controller it inherits from, naming hosts and the step types each one offers, choosing the default step drawing, the flow checks, and the admin pages.
21
- - **easy_flow-develop** owns building on it: declaring and registering step types, including ones that wait and ones with settings kept on the app's own records, moving a run on once what it waits for has happened, serving a host's flows from the app's own controllers and routes, and starting a run on a chosen published version, reading a visitor's run, its answers, the inner run it is waiting on and the output its flow ended with.
21
+ - **easy_flow-develop** owns building on it: declaring and registering step types, including ones that wait, ones that start another flow, and ones with settings kept on the app's own records, moving a run on once what it waits for has happened, serving a host's flows from the app's own controllers and routes, and starting a run on a chosen published version, reading a visitor's run, its answers, the inner run it is waiting on and the output its flow ended with.
22
22
 
23
23
  ## How to use it
24
24
 
25
25
  - To get easy_flow running in an app, or to change how it is configured, including which step types a host's admins can add, use **easy_flow-install**.
26
- - To add a step type, give a step type its own rule for refusing an answer, make what a step shows depend on the visitor's run, hold a run until something outside the flow has happened, keep a step's setting on one of the app's own records, put a flow on the app's own pages, start a run on a published version other than the live one, act on what a visitor answered, or act on the output a visitor's flow ended with, use **easy_flow-develop**.
26
+ - To add a step type, give a step type its own rule for refusing an answer, make what a step shows depend on the visitor's run, hold a run until something outside the flow has happened, add a step type of the app's own that starts another flow, keep a step's setting on one of the app's own records, put a flow on the app's own pages, start a run on a published version other than the live one, act on what a visitor answered, or act on the output a visitor's flow ended with, use **easy_flow-develop**.
27
27
  - To give a flow a different output for each way it can end, no code is needed: an admin fills in the output on each End step on the canvas.
28
28
  - To branch a flow on an answer or on a number the visitor gave, no code is needed: an admin places one of the built-in branching steps on the canvas.
29
29
  - To make a visitor answer a question or tick something on a checklist before going on, no code is needed: an admin marks that step as required on the canvas.
@@ -64,6 +64,7 @@ easy_flow declares no commands of its own for this local. Its surface is split b
64
64
  - **Flow step** — a built-in step that names another flow and the number of one of its versions. The admin picks the flow from the same host's flows, listed by title as the admin's list of flows shows them. The step has one connection for each different output the End steps of that version write, and none when no flow or version is picked or no End step there has an output. On the canvas its card is named after the flow's title and the version, such as "Onboarding, version 2", and is marked "Runs a flow". Once a flow is picked, clicking the card opens that flow's canvas, and the card's Settings button opens the step's own settings instead. A canvas opened from a Flow step's card shows a "Back to" button named after the title of the flow it was opened from, or its slug when it has no title, which returns to that flow's canvas. The button only appears when that flow belongs to the same host, and to the same owner when the host has one. While the admin is connecting steps, clicking the card picks it as the connection's target. A run that reaches a Flow step stops there. When the run is a stored run, it starts one inner run of the named flow on the picked version. A run that carries its answers in the page, and an admin's preview, stop at the Flow step, start no run, and never move past it.
65
65
  - **Unrunnable Flow step** — a Flow step whose picked flow or version cannot be run. Its card shows "missing flow" when no flow is picked or the picked flow no longer exists, and "unrunnable version" when the picked flow has no version with that number or that version is a draft, retired or withdrawn. These are always on, unlike the optional checks below, and the flow holding such a step cannot be saved as a new version or published until it is fixed.
66
66
  - **Circular Flow step** — a Flow step that leads back to the flow it sits in. That is either a Flow step naming its own flow, or one naming a flow whose picked version holds a Flow step that leads back the same way, through any number of flows. Each flow along the way is read at the version its Flow step picked. Its card shows "circular", and like an unrunnable Flow step this is always on and keeps the flow from being saved as a new version or published until it is fixed.
67
+ - **Flow-starting step type** — a step type of the app's own that starts another flow the way the Flow step does. By default it runs the flow and version named in its settings called flow and version. It may instead carry a rule that works out the flow and version from its other settings, and that choice is then used everywhere a Flow step's choice is: starting the inner run, the unrunnable and circular checks, and the canvas link to that flow. When the step type gives the step no name of its own, the step is named after the flow and version that rule works out, the same way a Flow step is, such as "Onboarding, version 2", on its canvas card and in the "Waiting for" line a visitor sees. Everything said below about a Flow step's inner run and handing back applies to it too.
67
68
  - **Inner run** — the run a Flow step starts. It records which run started it and at which step, and that run holds at most one inner run for each Flow step, however often it is moved on. It belongs to the same owner as the run that started it. When the picked version has been retired or withdrawn, no inner run is started and the run that reached the Flow step fails with an error naming that step. While the run that started it is stopped at the Flow step, that run can name the inner run it is waiting on, and it names none when it is stopped at any other step or has finished. Its steps that act on their own run as soon as it starts, and it stops at its first step that asks for input or waits.
68
69
  - **Handing back** — what happens when an inner run ends. Its flow output is recorded in the run that started it, as that run's answer at the Flow step, and a background job then moves that run on along the connection labelled with the output. An inner run that ended with no output records nothing in the run that started it, and the background job then fails with an error naming the Flow step, so that run does not move on. An output is handed back only once, so an inner run moved on again after it ended changes nothing. Because the move happens in a background job, the app must run its jobs for a run to go past a Flow step.
69
70
  - **Waiting step** — a step whose type carries a rule saying whether what it waits for has happened, such as a payment clearing or a document being signed. A run that reaches it stops there, and the visitor sees "Waiting for" followed by the step's name, with no form to submit. Once the rule says it has happened, the run moves past the step the next time the visitor's page is loaded or the app moves the run on, and the step is recorded as `true`.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: easy_flow-install
3
- description: Use to hook easy_flow into a project — copying and running its migrations, mounting the engine for each host, setting the controller it inherits from, declaring hosts with their layouts, access methods, the record that owns their flows and the step types each offers, choosing the default step drawing, turning on optional checks, giving the app a job queue that moves a run on once the flow its Flow step started ends, and reaching the admin pages.
3
+ description: Use to hook easy_flow into a project — copying and running its migrations, mounting the engine for each host, setting the controller it inherits from, declaring hosts with their layouts, access methods, the record that owns their flows and the step types each offers, choosing the default step drawing, turning on optional checks, giving the app a job queue that moves a run on once the flow its Flow step, or its own step type that starts a flow, started ends, and reaching the admin pages.
4
4
  tools: Bash, Read, Edit
5
5
  scope: guided flows — versioned documents of steps and the connections between them, drawn on a canvas by an admin and run by a visitor one step at a time, with step types the host registers
6
6
  ---
@@ -77,7 +77,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
77
77
  - It replaces the engine's drawing of every step whose type names no partial, so it draws each answer's hint and info itself or they are not shown.
78
78
  - It is not used for a checklist step. A checklist is always drawn by the engine as one checkbox per answer, each with an info button when the answer has info text, and the visitor may tick several.
79
79
  10. Leave `EasyFlow.check` out unless the developer asks for it. The engine already turns on `:unrouted_value`, `:unfollowed_path` and `:dead_end` at boot. Any other name raises `EasyFlow::UnknownCheck` when the app boots.
80
- 11. Check that the app loads Active Job (`require "rails/all"` or `require "active_job/railtie"` in `config/application.rb`) and has a queue adapter that runs jobs from the `default` queue. When a run started by a Flow step ends, the engine records its output in the run it was started from and queues a job on `default` that moves that run on. If no adapter runs that queue, the run that holds the Flow step stays at it. If `config.active_job.queue_adapter` is not set for an environment, ask the developer which adapter to use there.
80
+ 11. Check that the app loads Active Job (`require "rails/all"` or `require "active_job/railtie"` in `config/application.rb`) and has a queue adapter that runs jobs from the `default` queue. When a run started by a Flow step, or by a step type of the app's own that starts another flow, ends, the engine records its output in the run it was started from and queues a job on `default` that moves that run on. If no adapter runs that queue, the run that holds the step stays at it. If `config.active_job.queue_adapter` is not set for an environment, ask the developer which adapter to use there.
81
81
  12. Start the server and open `<mount path>/manage/flows` for each host.
82
82
 
83
83
  ## Conventions
@@ -101,6 +101,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
101
101
  - When a run reaches a Flow step whose chosen version was retired or withdrawn after the flow was published, the engine raises `EasyFlow::InnerFlowError` naming the Flow step and starts no run. The engine does not turn this error into a refusal, so the visitor gets the app's error page. Check that the app's error reporting captures it.
102
102
  - After install, check that removing a flow from `<mount path>/manage/flows` shows "Flow removed." and takes the flow off the list. Removing a flow deletes its versions and its runs, and needs no setting in the initializer.
103
103
  - After publishing a flow with a Flow step, check that while a run of it is stopped at that Flow step, removing the chosen flow is refused and the flow list shows "This flow cannot be removed while" followed by the waiting flow's title, or its slug when it has no title, and "waits on one of its runs". If no message is shown, check that the admin layout shows `flash[:alert]`.
104
+ - A step type of the app's own that starts another flow is treated as a Flow step by every check above: the "missing flow", "unrunnable version" and "circular" flags, the refusal to remove a flow a waiting run depends on, and the job on `default`. It runs the flow and version its own settings name, or the ones its declaration works out from its other settings, and needs no setting in the initializer beyond being listed in a host's `offers` when that host sets `offers`.
104
105
  - After setting a host's `offers`, check that the canvas palette on that host's `<mount path>/manage/flows` lists only those step types and End.
105
106
  - Taking a step type off a host's `offers` removes it from the palette only. Steps of that type already in the host's flows stay in them and keep running.
106
107
  - The initializer runs once at boot, so a change to it needs a server restart.
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.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tylercschneider