easy_flow 0.4.7 → 0.4.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.
- checksums.yaml +4 -4
- data/app/controllers/easy_flow/flows_controller.rb +8 -0
- data/app/models/easy_flow/digest.rb +1 -1
- data/app/models/easy_flow/run.rb +4 -0
- data/app/models/easy_flow/runner.rb +14 -2
- data/app/models/easy_flow/step_type/declaration.rb +5 -1
- data/app/models/easy_flow/step_type.rb +10 -1
- data/app/views/easy_flow/flows/step.html.erb +17 -13
- data/lib/easy_flow/version.rb +1 -1
- data/the_local/agents/easy_flow-develop.md +34 -4
- data/the_local/agents/easy_flow-info.md +6 -5
- data/the_local/agents/easy_flow-install.md +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f7ac7fa5bfb54fd32b37779b0ec07dcaf754d8d242fedac33fffa58e1c49d22
|
|
4
|
+
data.tar.gz: 9947469ec0272eccb7624372e102e6b60f9a93ebbe08572846246f8ae956eb56
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2ec1059bd29bcd076aef6df9a4f713690ebd7e8bb786e1c05bf51d9991b23f497c3e83bfb4aad12063168b9d5fdf96f4a265dbe1cb496a7fbe5a4238053db9aa
|
|
7
|
+
data.tar.gz: ea9a2e1eabb38ccad3426bb487f8a9e1933eb83e4c4d98920868e926e5f963d7eefd4aeed3604663f2c1b47e5651c84f458a19a5fe2abd044d664fd755634ef4
|
|
@@ -18,6 +18,7 @@ module EasyFlow
|
|
|
18
18
|
@question = @guide.next_step(@answers)
|
|
19
19
|
@drawing = @guide.drawing_at(@answers)
|
|
20
20
|
flash.now[:alert] = @refused if @refused
|
|
21
|
+
@waiting = waiting_on(@question)
|
|
21
22
|
return render :step if @question
|
|
22
23
|
|
|
23
24
|
render_completion
|
|
@@ -124,6 +125,13 @@ module EasyFlow
|
|
|
124
125
|
progress.record(id, value.to_s)
|
|
125
126
|
end
|
|
126
127
|
|
|
128
|
+
def waiting_on(step)
|
|
129
|
+
return unless step.respond_to?(:type) && EasyFlow.registry.registered?(step.type)
|
|
130
|
+
|
|
131
|
+
step_type = EasyFlow.registry.fetch(step.type)
|
|
132
|
+
step_type.name_of(step).presence || step_type.step_name if step_type.waits?
|
|
133
|
+
end
|
|
134
|
+
|
|
127
135
|
def answer_problem(step, answer)
|
|
128
136
|
return unless step && EasyFlow.registry.registered?(step.type)
|
|
129
137
|
|
data/app/models/easy_flow/run.rb
CHANGED
|
@@ -27,8 +27,8 @@ module EasyFlow
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def run(progress)
|
|
30
|
-
while (node = @digest.next_step(named(progress.recorded))) &&
|
|
31
|
-
progress.record(node.id,
|
|
30
|
+
while (node = @digest.next_step(named(progress.recorded))) && goes_on?(node, named(progress.recorded))
|
|
31
|
+
progress.record(node.id, result_of(node, named(progress.recorded)))
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -50,6 +50,18 @@ module EasyFlow
|
|
|
50
50
|
@registry.registered?(node.type) && @registry.fetch(node.type).acts?
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
def goes_on?(node, state)
|
|
54
|
+
acts?(node) || ready?(node, state)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def ready?(node, state)
|
|
58
|
+
@registry.registered?(node.type) && @registry.fetch(node.type).waits? && @registry.fetch(node.type).ready?(node, state)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def result_of(node, state)
|
|
62
|
+
acts?(node) ? @registry.fetch(node.type).process(node, state) : true
|
|
63
|
+
end
|
|
64
|
+
|
|
53
65
|
def shown(node)
|
|
54
66
|
return node unless node && @registry.registered?(node.type)
|
|
55
67
|
|
|
@@ -44,6 +44,10 @@ module EasyFlow
|
|
|
44
44
|
@answer_check = check
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
def waits_until(&readiness)
|
|
48
|
+
@readiness = readiness
|
|
49
|
+
end
|
|
50
|
+
|
|
47
51
|
def step_name(value)
|
|
48
52
|
@step_name = value
|
|
49
53
|
end
|
|
@@ -107,7 +111,7 @@ module EasyFlow
|
|
|
107
111
|
StepType.new(id: @id, step_name: @step_name, settings: settings, awaits_input: @awaits_input,
|
|
108
112
|
ends_here: @ends_here, begins_here: @begins_here, behaviour: @behaviour, routing: @routing,
|
|
109
113
|
display: @display, drawn_by: @drawn_by, naming_field: @naming_field, naming: @naming,
|
|
110
|
-
outputs: @declared_outputs, answer_check: @answer_check)
|
|
114
|
+
outputs: @declared_outputs, answer_check: @answer_check, readiness: @readiness)
|
|
111
115
|
end
|
|
112
116
|
|
|
113
117
|
def settings
|
|
@@ -8,7 +8,7 @@ module EasyFlow
|
|
|
8
8
|
|
|
9
9
|
def initialize(id:, step_name:, settings:, awaits_input:, behaviour:, routing:,
|
|
10
10
|
ends_here: false, begins_here: false, display: nil, drawn_by: nil,
|
|
11
|
-
naming_field: nil, naming: nil, outputs: [], answer_check: nil)
|
|
11
|
+
naming_field: nil, naming: nil, outputs: [], answer_check: nil, readiness: nil)
|
|
12
12
|
@id = id
|
|
13
13
|
@step_name = step_name
|
|
14
14
|
@settings = settings
|
|
@@ -23,6 +23,7 @@ module EasyFlow
|
|
|
23
23
|
@naming = naming
|
|
24
24
|
@outputs = outputs
|
|
25
25
|
@answer_check = answer_check
|
|
26
|
+
@readiness = readiness
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def display_of(node)
|
|
@@ -41,6 +42,14 @@ module EasyFlow
|
|
|
41
42
|
@answer_check&.call(node, value)
|
|
42
43
|
end
|
|
43
44
|
|
|
45
|
+
def waits?
|
|
46
|
+
@readiness.present?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def ready?(node, state)
|
|
50
|
+
@readiness.call(node, state)
|
|
51
|
+
end
|
|
52
|
+
|
|
44
53
|
def name_of(node)
|
|
45
54
|
@naming&.call(node).presence || node.config[naming_field.to_s].presence
|
|
46
55
|
end
|
|
@@ -11,22 +11,26 @@
|
|
|
11
11
|
<div class="mb-6"><%= ui_alert(message: flash[:alert], type: :error) %></div>
|
|
12
12
|
<% end %>
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
<% if @waiting %>
|
|
15
|
+
<p class="text-gray-700">Waiting for <%= @waiting %>.</p>
|
|
16
|
+
<% else %>
|
|
17
|
+
<%= form_with url: step_form[:url], method: step_form[:method], data: { turbo: false } do %>
|
|
18
|
+
<%= hidden_field_tag :asked, @question.id %>
|
|
19
|
+
<% if carries_answers? %>
|
|
20
|
+
<% @answers.each do |key, value| %>
|
|
21
|
+
<%= hidden_field_tag "answers[#{key}]", value %>
|
|
22
|
+
<% end %>
|
|
19
23
|
<% end %>
|
|
20
|
-
<% end %>
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
<%= render @drawing, step: @question %>
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
<div class="mt-8 flex items-center gap-4">
|
|
28
|
+
<%= ui_button(label: "Next", type: :submit) %>
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
<% if @answers.any? %>
|
|
31
|
+
<button type="submit" name="back" value="1" formnovalidate class="cursor-pointer text-sm text-gray-500 underline underline-offset-2 hover:text-gray-900">← Back</button>
|
|
32
|
+
<% end %>
|
|
33
|
+
</div>
|
|
34
|
+
<% end %>
|
|
31
35
|
<% end %>
|
|
32
36
|
<% end %>
|
data/lib/easy_flow/version.rb
CHANGED
|
@@ -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, computes a value from earlier answers,
|
|
3
|
+
description: Use PROACTIVELY for adding a step type to easy_flow flows (a step that asks the visitor something, computes a value from earlier answers, picks the next branch, or holds the visitor until something outside the flow has happened), 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, serving a host's flows from the app's own controller and routes, acting when a visitor finishes a flow, and reading a run's recorded answers and question labels — MUST BE USED instead of hand-rolling questionnaire steps, branching logic, number comparisons, hard-coded setting options, 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
|
---
|
|
@@ -18,7 +18,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
18
18
|
- `EasyFlow::FlowsController` — the visitor controller; the app subclasses it to serve one host's flows from its own routes and to change what happens at the start, on each step and at the finish.
|
|
19
19
|
- `hosted_by` — class method on a `FlowsController` subclass naming the host whose flows it serves.
|
|
20
20
|
- `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.
|
|
21
|
-
- `EasyFlow::Run` — the stored record of one visitor's pass through a flow, pinned to the version that was live when it started
|
|
21
|
+
- `EasyFlow::Run` — the stored record of one visitor's pass through a flow, pinned to the version that was live when it started, and moved on past a waiting step with `advance`.
|
|
22
22
|
- `EasyFlow::QuestionRunner` — reads a flow document: its steps, the next step for a set of answers, the answers on the path taken, and a question's text and an answer's label.
|
|
23
23
|
|
|
24
24
|
## How to use it
|
|
@@ -29,7 +29,8 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
29
29
|
- It asks the visitor for input — declare `awaits_input`.
|
|
30
30
|
- It computes a value from earlier answers with no visitor input — define `process`.
|
|
31
31
|
- It only picks which connection to follow — define `route`.
|
|
32
|
-
|
|
32
|
+
- It holds the visitor until something outside the flow has happened, such as a payment arriving or a reviewer approving — declare `waits_until`.
|
|
33
|
+
A type may both `process` and `route`. A type that does none of the four is passed through without stopping when a visitor reaches it.
|
|
33
34
|
2. Create the class in the app, for example `app/models/flow_steps/rating.rb`. The class name, underscored, is the type's id (`Rating` becomes `:rating`), and that id is stored in every flow that uses it, so it must not change after admins start using the type. It must not be one of the built-in ids `start`, `terminal`, `question`, `condition`, `switch` or `compare`:
|
|
34
35
|
|
|
35
36
|
```ruby
|
|
@@ -78,6 +79,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
78
79
|
- `output :name, type:, label:, values:, from:` — a value the step records. `type` is one of `:string`, `:integer`, `:float`, `:boolean`, or boot raises `EasyFlow::UnknownOutputType`. `values:` is an array or a lambda taking the node, listing the values the output can take; the canvas offers these as the connections leaving the step, so a type that routes must declare them. `from: :<setting>` takes the values from the step chosen in that setting.
|
|
79
80
|
- `names_by :setting` or `names_by { |node| ... }` — what the step is called on the canvas, from a setting or computed.
|
|
80
81
|
- `awaits_input` — the visitor is shown this step and submits an answer to it.
|
|
82
|
+
- `waits_until { |node, state| ... }` — the run stops at this step until the block returns a truthy value. See step 7.
|
|
81
83
|
- `answer_check { |node, value| ... }` — checks a submitted answer before it is recorded. `value` is the submitted string, or `nil` when the input sent nothing. Return a message to refuse the answer, or `nil` to accept it. Without it every answer is accepted, including a blank one.
|
|
82
84
|
- `ends_here` / `begins_here` — marks the type as an end or a start of a flow.
|
|
83
85
|
- `displays_by { |node| ... }` — builds the object handed to the step's partial as the local `step`. Without it the partial receives the node itself.
|
|
@@ -116,7 +118,31 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
116
118
|
setting :required, type: :boolean
|
|
117
119
|
answer_check { |node, value| "Fill this in to go on." if node.config["required"] && value.blank? }
|
|
118
120
|
```
|
|
119
|
-
7.
|
|
121
|
+
7. For a type that waits, declare `waits_until` with a block that says whether what the step waits for has happened:
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
module FlowSteps
|
|
125
|
+
class AwaitPayment
|
|
126
|
+
include EasyFlow::Step
|
|
127
|
+
|
|
128
|
+
step_name "Payment"
|
|
129
|
+
|
|
130
|
+
setting :invoice_step, type: :previous_step
|
|
131
|
+
|
|
132
|
+
waits_until { |node, state| Invoice.paid?(state[node.config["invoice_step"]]) }
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- 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.
|
|
138
|
+
- 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.
|
|
139
|
+
- 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.
|
|
140
|
+
- 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.
|
|
141
|
+
- Do not declare `awaits_input` on a type that waits. The waiting message replaces the form, so the input is never shown.
|
|
142
|
+
- The page does not reload itself. Ask the developer how the run should move on when what it waits for happens:
|
|
143
|
+
- The visitor reloads the page. This needs nothing more, and works whether or not the flow keeps a stored run.
|
|
144
|
+
- 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.
|
|
145
|
+
8. Restart the server, open a flow on the canvas and check the type is offered, its settings show, and a preview walks through it.
|
|
120
146
|
|
|
121
147
|
### Serve a host's flows from the app's own controller
|
|
122
148
|
|
|
@@ -162,6 +188,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
162
188
|
- `run.owner` — the optional record the run belongs to, polymorphic, set by the app. `run.label` and `run.status` are free string columns for the app's own use.
|
|
163
189
|
- `run.pinned_definition` — the flow document of the version the run started on.
|
|
164
190
|
- `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.
|
|
191
|
+
- `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.
|
|
165
192
|
3. To show answers with their question text and answer labels, build a runner from the run's pinned document:
|
|
166
193
|
|
|
167
194
|
```ruby
|
|
@@ -187,5 +214,8 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
187
214
|
- Always look flows and runs up through a host.
|
|
188
215
|
- A step's input field is named `answers[<step id>]` and submits one value. Any other name is ignored, and an array or hash is treated as blank.
|
|
189
216
|
- An answer the type's `answer_check` refuses is never recorded, and the visitor is shown the same step with the check's message. An answer no check refuses is recorded, a blank one as `""`.
|
|
217
|
+
- A `waits_until` block is given only the step and the answers recorded so far, so what it waits for must be findable from those.
|
|
218
|
+
- A type that waits never also declares `awaits_input`.
|
|
219
|
+
- `run.advance` only moves a stored run, and never finishes it; the visitor's next page load does.
|
|
190
220
|
- A `FlowsController` subclass needs all four named routes for its prefix; a missing one raises when the visitor is linked or redirected to it.
|
|
191
221
|
- The engine installs, mounts and configures hosts, layouts, the default drawing and checks through `easy_flow-install`, not here.
|
|
@@ -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, hosts, runs, the built-in step types including questions that can require an answer and branching on an answer or comparing a number, step types the host app registers
|
|
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, hosts, runs, the built-in step types including questions that can require an answer and branching on an answer or comparing a number, step types the host app registers, the checks they make on an answer, 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.
|
|
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
|
---
|
|
@@ -11,19 +11,19 @@ This local explains easy_flow and the words it uses. It makes no changes and giv
|
|
|
11
11
|
|
|
12
12
|
easy_flow is a Rails engine for guided, branching flows. An admin builds a flow on a canvas by placing steps and connecting them, previews it, and publishes it. A visitor then walks the published flow one step at a time, and each answer decides which step comes next.
|
|
13
13
|
|
|
14
|
-
Reach for it when an app needs a questionnaire, an intake form, or any decision path that an admin should be able to change without a deploy. The engine ships a start step, an end step, a question step, and three steps that pick a branch from earlier answers. Anything else a flow needs to ask or
|
|
14
|
+
Reach for it when an app needs a questionnaire, an intake form, or any decision path that an admin should be able to change without a deploy. The engine ships a start step, an end step, a question step, and three steps that pick a branch from earlier answers. Anything else a flow needs to ask, do, or wait for is a step type the app declares itself.
|
|
15
15
|
|
|
16
16
|
## Interface
|
|
17
17
|
|
|
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, 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, serving a host's flows from the app's own controllers and routes, and reading a visitor's run and answers.
|
|
21
|
+
- **easy_flow-develop** owns building on it: declaring and registering step types, including ones that wait, 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 reading a visitor's run and answers.
|
|
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, use **easy_flow-install**.
|
|
26
|
-
- To add a step type, give a step type its own rule for refusing an answer, put a flow on the app's own pages, or act on what a visitor answered, use **easy_flow-develop**.
|
|
26
|
+
- To add a step type, give a step type its own rule for refusing an answer, hold a run until something outside the flow has happened, put a flow on the app's own pages, or act on what a visitor answered, use **easy_flow-develop**.
|
|
27
27
|
- 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.
|
|
28
28
|
- To make a visitor answer a question before going on, no code is needed: an admin marks that question step as required on the canvas.
|
|
29
29
|
- If the question is only what a word below means, this page is the answer.
|
|
@@ -35,7 +35,7 @@ easy_flow declares no commands of its own for this local. Its surface is split b
|
|
|
35
35
|
- **Version** — a numbered snapshot of the document. A version is a draft until it is published, and a flow has at most one live version at a time.
|
|
36
36
|
- **Canvas** — the admin screen where steps are added, configured, moved, removed and connected, with undo and redo. Publishing happens there.
|
|
37
37
|
- **Preview** — an admin walking the current flow without starting a stored run.
|
|
38
|
-
- **Step type** — what a kind of step is: its display name, its settings (the fields an admin fills in), its outputs (the values it records), and whether it waits for the visitor
|
|
38
|
+
- **Step type** — what a kind of step is: its display name, its settings (the fields an admin fills in), its outputs (the values it records), and whether it waits for the visitor, acts on its own, or waits for something outside the flow. A step that acts on its own may record a value worked out from the answers so far, pick which connection to follow, or both.
|
|
39
39
|
- **Answer check** — a rule a step type may carry that looks at a visitor's answer and, when the answer is not acceptable, returns the message the visitor sees. A step type with no such rule accepts every answer.
|
|
40
40
|
- **Setting** — one field an admin fills in when configuring a step on the canvas. It is text, a whole number, a decimal, a yes or no, a pick from a list, several picks from a list, an earlier step, an earlier step's output, or a list of entries that each hold their own fields. A setting can be required, limited to a number of picks, or checked by a rule the step type supplies.
|
|
41
41
|
- **Options** — the values a pick-from-a-list setting offers. They are either a fixed list written into the step type, or a lookup the app provides that is read each time the canvas or a save asks for them, so they can come from the app's own data. A saved value that is not among the options is refused.
|
|
@@ -46,6 +46,7 @@ easy_flow declares no commands of its own for this local. Its surface is split b
|
|
|
46
46
|
- **Condition** — a built-in branching step that checks whether an earlier step's answer is, or is not, a chosen value, and follows the true or the false connection.
|
|
47
47
|
- **Switch** — a built-in branching step that follows the connection labelled with an earlier step's answer.
|
|
48
48
|
- **Compare** — a built-in branching step that reads an earlier step's answer as a number and checks it against an amount by more than, less than, at least or at most, then follows the true or the false connection. When the earlier step recorded several outputs, the admin picks which one. An answer that is missing or is not a number decides false.
|
|
49
|
+
- **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`.
|
|
49
50
|
- **Registry** — the list of step types the app has registered, alongside the built-in ones. A step whose type is not registered is not shown or run as that type, and its answers are not checked.
|
|
50
51
|
- **Host** — a named part of the app that owns a set of flows. A host sets the visitor layout and the admin layout, how admins are authenticated, how visitors are authorized, and how a refusal is answered. Flows are always looked up through a host, so one host never sees another's flows.
|
|
51
52
|
- **Run** — one visitor's pass through a flow. A run is pinned to the version that was live when it started, so publishing a new version does not change a run already under way. It records each answer by step id, and going back discards the last answer on the path.
|
|
@@ -60,7 +60,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
|
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
A mount whose host name is not declared serves no flows, and its admin pages return `404 Not Found`.
|
|
63
|
-
8. Ask the developer whether visitors' steps should be drawn with the engine's own partial or with one from the app. For the app's own, create a partial, for example `app/views/steps/_step.html.erb`, which receives the step as the local `step`. Then add to the initializer:
|
|
63
|
+
8. Ask the developer whether visitors' steps should be drawn with the engine's own partial or with one from the app. For the app's own, create a partial, for example `app/views/steps/_step.html.erb`, which receives the step as the local `step`. It is rendered inside the engine's form, so it draws only the fields, and the visitor's answer must be submitted as `answers[<%= step.id %>]`. Then add to the initializer:
|
|
64
64
|
|
|
65
65
|
```ruby
|
|
66
66
|
EasyFlow.draws_with("steps/step")
|