easy_flow 0.4.3 → 0.4.4
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/Rakefile +2 -0
- data/lib/easy_flow/version.rb +1 -1
- data/the_local/agents/easy_flow-develop.md +175 -0
- data/the_local/agents/easy_flow-info.md +42 -0
- data/the_local/agents/easy_flow-install.md +78 -0
- data/the_local/interface.yml +40 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7d14521622c3830ea4e9608d08eaa8b8d90125cd898bdf8aa8547b09a80aa905
|
|
4
|
+
data.tar.gz: cd223813e0562b015871a7b614fc9ae343a954fd52ec44b06e2197fd6f758297
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e2b3b92295289c74be0bbde30055366b5c9d59c07378bda7347d723c4e8dc6a74a5fb15681cde91345f35ed17816e46995ceb2f9bc323221e5b7655a0efe320b
|
|
7
|
+
data.tar.gz: 3f8e757df44027f931efd503d54f1640a486e6cd9b2f56825f4c95b9036d2653731d5318b28ac16de701b93e0861b1bc41d07c4ca9c8192a00cc5cca24e3aad8
|
data/Rakefile
CHANGED
data/lib/easy_flow/version.rb
CHANGED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
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, or picks the next branch), 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, flow controllers or answer lookups.
|
|
4
|
+
tools: Read, Write, Edit, Grep
|
|
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
|
+
---
|
|
7
|
+
|
|
8
|
+
This local follows the steps below exactly and invents none. Where a step names a decision, it asks the developer and does not pick.
|
|
9
|
+
|
|
10
|
+
## What easy_flow is
|
|
11
|
+
|
|
12
|
+
A Rails engine for flows an admin draws on a canvas and a visitor runs one step at a time. Each step is an instance of a step type, and the engine ships the question type (a question with a list of answers) plus its own start, end, condition and switch types. Use this local when the app needs a step type of its own, needs a host's flows on its own pages with its own behaviour when a visitor finishes, or needs to read what a visitor answered. It assumes easy_flow is already installed and a host is declared; if not, hand off to `easy_flow-install` first.
|
|
13
|
+
|
|
14
|
+
## Interface
|
|
15
|
+
|
|
16
|
+
- `EasyFlow::Step` — a module a class includes to declare a step type with class-level words, registered with `.register`.
|
|
17
|
+
- `EasyFlow.step` — declares and registers a step type in one call from a block of the same words, for a type small enough not to need its own class.
|
|
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
|
+
- `hosted_by` — class method on a `FlowsController` subclass naming the host whose flows it serves.
|
|
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.
|
|
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
|
+
|
|
24
|
+
## How to use it
|
|
25
|
+
|
|
26
|
+
### Declare a step type
|
|
27
|
+
|
|
28
|
+
1. Ask the developer what the step does, and which of these it is:
|
|
29
|
+
- It asks the visitor for input — declare `awaits_input`.
|
|
30
|
+
- It computes a value from earlier answers with no visitor input — define `process`.
|
|
31
|
+
- It only picks which connection to follow — define `route`.
|
|
32
|
+
A type may both `process` and `route`. A type that does none of the three is skipped when a visitor reaches it.
|
|
33
|
+
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:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
module FlowSteps
|
|
37
|
+
class Rating
|
|
38
|
+
include EasyFlow::Step
|
|
39
|
+
|
|
40
|
+
step_name "Rating"
|
|
41
|
+
|
|
42
|
+
setting :prompt, type: :string, required: true
|
|
43
|
+
setting :scale, type: :select, options: %w[5 10], required: true
|
|
44
|
+
|
|
45
|
+
output :score, type: :integer, label: "Score"
|
|
46
|
+
|
|
47
|
+
names_by :prompt
|
|
48
|
+
awaits_input
|
|
49
|
+
drawn_by "flow_steps/rating"
|
|
50
|
+
|
|
51
|
+
displays_by { |node| RatingPrompt.new(id: node.id, text: node.config["prompt"], scale: node.config["scale"].to_i) }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For a small type with no methods of its own, the block form declares and registers in one call instead of a class and step 3:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
EasyFlow.step(:note) do
|
|
60
|
+
step_name "Note"
|
|
61
|
+
setting :text, type: :string
|
|
62
|
+
awaits_input
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
3. Register each class-based type in `config/initializers/easy_flow.rb` inside `to_prepare`, so it is registered again after a code reload:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
Rails.application.config.to_prepare do
|
|
70
|
+
FlowSteps::Rating.register
|
|
71
|
+
end
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
A step whose type is not registered is neither shown nor run as that type.
|
|
75
|
+
4. Use these words to declare the type. Each is called once at class level (or inside the `EasyFlow.step` block):
|
|
76
|
+
- `step_name "<label>"` — the name admins see on the canvas. Defaults to the id.
|
|
77
|
+
- `setting :name, type:, label:, options:, required:, limit:, check:, from:, outputs_of:` — a field the admin fills in on the canvas. `type` is one of `:string`, `:integer`, `:float`, `:boolean`, `:select`, `:multi_select`, `:previous_step`, `:from_step`, `:list`. A `:select` or `:multi_select` must pass `options:`, or boot raises `EasyFlow::UnknownFieldType`. A `:list` must take a block of `setting` calls describing one entry. `:previous_step` lets the admin pick an earlier step. `outputs_of: :<setting>` offers the outputs of the step chosen in that setting, and `from: :<setting>` offers the values of the output chosen in that setting; either one makes the type `:from_step`.
|
|
78
|
+
- `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. `from: :<setting>` takes the values from the step chosen in that setting.
|
|
79
|
+
- `names_by :setting` or `names_by { |node| ... }` — what the step is called on the canvas, from a setting or computed.
|
|
80
|
+
- `awaits_input` — the visitor is shown this step and must answer it.
|
|
81
|
+
- `ends_here` / `begins_here` — marks the type as an end or a start of a flow.
|
|
82
|
+
- `displays_by { |node| ... }` — builds the object handed to the step's partial as the local `step`. Without it the partial receives the node itself.
|
|
83
|
+
- `drawn_by "<partial>"` — the partial that draws this type for a visitor. Without it the host's default drawing is used, which expects `step.id`, `step.text` and `step.choices`, so a type with its own display shape needs its own partial.
|
|
84
|
+
5. For a type that computes or routes, define instance methods on the class (or `process { |node, state| ... }` / `route { |node, state| ... }` in the block form):
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
def process(node, state)
|
|
88
|
+
state[node.config["step"]].to_i * 2
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def route(node, state)
|
|
92
|
+
state[node.config["step"]] == node.config["answer"]
|
|
93
|
+
end
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- `node` has `id`, `type` and `config`; `config` is a hash of the admin's settings with string keys.
|
|
97
|
+
- `state` is the answers recorded so far, keyed by step id as strings.
|
|
98
|
+
- `process` returns the value recorded under this step's id. It runs as soon as a visitor reaches the step, before the next step is shown.
|
|
99
|
+
- `route` returns the value that picks the connection to follow; it is compared as a string with the value each leaving connection is labelled with. Returning `nil` follows the first connection.
|
|
100
|
+
6. For a type that awaits input, write the partial named in `drawn_by`, for example `app/views/flow_steps/_rating.html.erb`. It receives the display object as `step`. It renders only the input, since the page supplies the form, the Next button and the Back button. The input must be named `answers[<step id>]`, or the answer is not recorded:
|
|
101
|
+
|
|
102
|
+
```erb
|
|
103
|
+
<%= label_tag "answers[#{step.id}]", step.text %>
|
|
104
|
+
<%= number_field_tag "answers[#{step.id}]", nil, in: 1..step.scale %>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
7. Restart the server, open a flow on the canvas and check the type is offered, its settings show, and a preview walks through it.
|
|
108
|
+
|
|
109
|
+
### Serve a host's flows from the app's own controller
|
|
110
|
+
|
|
111
|
+
1. Ask the developer which host this controller serves, what path the visitor pages live under, and what should happen when a visitor finishes. Do not choose the finish behaviour for them.
|
|
112
|
+
2. Add the routes in `config/routes.rb`. The names must be the prefix followed by `_flow`, `_flow_step`, `_flow_runs` and `_run`, because the controller builds every link and redirect from those four:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
get "intake/:slug", to: "intake_flows#show", as: :intake_flow
|
|
116
|
+
get "intake/:slug/step", to: "intake_flows#step", as: :intake_flow_step
|
|
117
|
+
post "intake/:slug/runs", to: "intake_flows#start", as: :intake_flow_runs
|
|
118
|
+
get "intake/runs/:id", to: "intake_flows#step", as: :intake_run
|
|
119
|
+
patch "intake/runs/:id", to: "intake_flows#update"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
3. Create the controller, naming the host with `hosted_by` and the route prefix with `routed_by`:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
class IntakeFlowsController < EasyFlow::FlowsController
|
|
126
|
+
hosted_by :intake
|
|
127
|
+
routed_by :intake
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def finished(answers, run)
|
|
132
|
+
redirect_to main_app.intake_summary_path(run)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The controller inherits from the base controller set at install, uses the host's layout, visitor authorization and refusal methods, and only finds flows that belong to the named host. Pages it does not override use the engine's own views.
|
|
138
|
+
4. Override only the private methods the developer's answers call for:
|
|
139
|
+
- `finished(answers, run)` — called when the visitor reaches the end. `answers` is the answers on the path taken, keyed by step id as symbols. `run` is the stored `EasyFlow::Run`, or `nil` when the flow keeps no record. It must render or redirect. Default: the engine's completion page.
|
|
140
|
+
- `start_run(flow)` — creates the run when a visitor starts a flow that saves each step. Call `super` and change the run it returns, for example to set its `owner` or `label`.
|
|
141
|
+
- `runner_for(definition)` — returns the runner used for each step. Return a subclass of `EasyFlow::QuestionRunner` to change what the step and completion pages read from it.
|
|
142
|
+
5. Visit `/<path>/<slug>` for a published flow and walk it to the end.
|
|
143
|
+
|
|
144
|
+
### Read a run and its answers
|
|
145
|
+
|
|
146
|
+
1. Find runs scoped to one host so one host never sees another's: `EasyFlow::Run.joins(:flow).where(easy_flow_definitions: { host: "intake" })`.
|
|
147
|
+
2. Read from a run:
|
|
148
|
+
- `run.recorded` — the answers so far, a hash keyed by step id as symbols.
|
|
149
|
+
- `run.flow` — the flow it belongs to.
|
|
150
|
+
- `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.
|
|
151
|
+
- `run.pinned_definition` — the flow document of the version the run started on.
|
|
152
|
+
- `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.
|
|
153
|
+
3. To show answers with their question text and answer labels, build a runner from the run's pinned document:
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
runner = EasyFlow::QuestionRunner.new(run.pinned_definition)
|
|
157
|
+
runner.state_on_path(run.recorded).each do |step_id, value|
|
|
158
|
+
puts "#{runner.question_text(step_id)}: #{runner.choice_label(step_id, value)}"
|
|
159
|
+
end
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- `state_on_path(answers)` — only the answers on the path the visitor actually took, dropping answers left behind by going back.
|
|
163
|
+
- `question_text(id)` — the text of a question step. It returns `nil` for a step of any other type.
|
|
164
|
+
- `choice_label(id, value)` — the label of the chosen answer, or the value itself when there is no label.
|
|
165
|
+
- `steps`, `step(id)`, `next_step(answers)`, `steps_on_path(answers)`, `slug` and `headline` read the rest of the document.
|
|
166
|
+
|
|
167
|
+
## Conventions
|
|
168
|
+
|
|
169
|
+
- A step type's id comes from its class name or the id passed to `EasyFlow.step`, and it is stored in flow documents, so renaming the class or id breaks every flow that uses it.
|
|
170
|
+
- Register class-based step types inside `to_prepare`. A type registered anywhere else is lost on code reload in development.
|
|
171
|
+
- Always read a run against `run.pinned_definition`, never the flow's live version, since a run keeps the version it started on after a new one is published.
|
|
172
|
+
- Always look flows and runs up through a host.
|
|
173
|
+
- A step's input field is named `answers[<step id>]`. Any other name is ignored.
|
|
174
|
+
- A `FlowsController` subclass needs all four named routes for its prefix; a missing one raises when the visitor is linked or redirected to it.
|
|
175
|
+
- The engine installs, mounts and configures hosts, layouts, the default drawing and checks through `easy_flow-install`, not here.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
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, and step types the host app registers.
|
|
4
|
+
tools: Read
|
|
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
|
+
---
|
|
7
|
+
|
|
8
|
+
This local explains easy_flow and the words it uses. It makes no changes and gives no steps.
|
|
9
|
+
|
|
10
|
+
## What easy_flow is
|
|
11
|
+
|
|
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
|
+
|
|
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 one step type, a question with a list of answers. Anything else a flow needs to ask or do is a step type the app declares itself.
|
|
15
|
+
|
|
16
|
+
## Interface
|
|
17
|
+
|
|
18
|
+
easy_flow declares no commands of its own for this local. Its surface is split between the other two:
|
|
19
|
+
|
|
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 canvas drawing, turning on optional 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.
|
|
22
|
+
|
|
23
|
+
## How to use it
|
|
24
|
+
|
|
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, put a flow on the app's own pages, or act on what a visitor answered, use **easy_flow-develop**.
|
|
27
|
+
- If the question is only what a word below means, this page is the answer.
|
|
28
|
+
|
|
29
|
+
## Conventions
|
|
30
|
+
|
|
31
|
+
- **Flow** — one guided path, found by its slug. It holds a working document the admin edits and a list of versions.
|
|
32
|
+
- **Document** — the flow's content: its steps (nodes), the connections between them (edges), a headline and a slug.
|
|
33
|
+
- **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.
|
|
34
|
+
- **Canvas** — the admin screen where steps are added, configured, moved, removed and connected, with undo and redo. Publishing happens there.
|
|
35
|
+
- **Preview** — an admin walking the current flow without starting a stored run.
|
|
36
|
+
- **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 or acts on its own. A step that acts on its own processes the answers so far and records a result, and a step type may also decide its own routing.
|
|
37
|
+
- **Question** — the built-in step type: a question text and a list of answers, each with a value, a label and a weight.
|
|
38
|
+
- **Registry** — the list of step types the app has registered. A step whose type is not registered is not shown or run as that type.
|
|
39
|
+
- **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.
|
|
40
|
+
- **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.
|
|
41
|
+
- **Answers** — the recorded state of a run, keyed by step id. The next step is always worked out from these answers and the connections in the pinned version.
|
|
42
|
+
- **Checks** — optional warnings on a flow's shape an app can turn on: an answer value no connection routes, a path nothing follows, and a step that leads nowhere.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
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 and access methods, choosing the default step drawing, turning on optional checks, and reaching the admin pages.
|
|
4
|
+
tools: Bash, Read, Edit
|
|
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
|
+
---
|
|
7
|
+
|
|
8
|
+
This local follows the steps below exactly and invents none. Where a step names a decision, it asks the developer and does not pick.
|
|
9
|
+
|
|
10
|
+
## What easy_flow is
|
|
11
|
+
|
|
12
|
+
A Rails engine for flows an admin draws on a canvas and a visitor runs one step at a time. Hook it in when a Rails 8.1 app needs questionnaires, intake forms or decision paths that admins change without a deploy.
|
|
13
|
+
|
|
14
|
+
## Interface
|
|
15
|
+
|
|
16
|
+
- `bin/rails easy_flow:install:migrations` — copies the engine's migrations into the host's `db/migrate`, creating the flow, version and run tables.
|
|
17
|
+
- `mount EasyFlow::Engine` — the route that serves one host's visitor pages and admin pages under a path, with the host named in `defaults: { easy_flow_host: "<host>" }`.
|
|
18
|
+
- `EasyFlow.base_controller=` — the name, as a string, of the host controller every engine controller inherits from. Defaults to `"ActionController::Base"`.
|
|
19
|
+
- `EasyFlow.host` — declares a named host with its visitor layout, admin layout, admin authentication method, visitor authorization method and refusal method.
|
|
20
|
+
- `EasyFlow.draws_with` — the partial that draws a visitor's step when the step's type names none. Defaults to the engine's own `easy_flow/steps/choosing`.
|
|
21
|
+
- `EasyFlow.check` — turns on an optional flow check: `:unrouted_value`, `:unfollowed_path` or `:dead_end`.
|
|
22
|
+
- `/manage/flows` — the admin pages, under each mount path, where flows are listed, created, drawn on the canvas, previewed and published.
|
|
23
|
+
|
|
24
|
+
## How to use it
|
|
25
|
+
|
|
26
|
+
1. Confirm the app has Keystone UI installed (`keystone_ui` in the Gemfile). easy_flow's controllers use its helpers and it is not pulled in by easy_flow. If it is missing, stop and hand off to the `keystone_ui-install` local before continuing.
|
|
27
|
+
2. Add `gem "easy_flow"` to the host's `Gemfile` and run `bundle install`.
|
|
28
|
+
3. Run `bin/rails easy_flow:install:migrations`, then `bin/rails db:migrate`. This writes four migrations into `db/migrate` and updates `db/schema.rb`.
|
|
29
|
+
4. Ask the developer which hosts the app needs. A host is one part of the app that owns its own set of flows, and one host never sees another's flows. Ask for each host's name and the path it is served under.
|
|
30
|
+
5. Ask the developer which controller the engine should inherit from. Choosing `"ApplicationController"` gives the engine the app's own authentication methods and helpers. Create `config/initializers/easy_flow.rb` and set it on the first line:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
EasyFlow.base_controller = "ApplicationController"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
6. In the same initializer, declare each host. Every setting is optional. Ask the developer for each value and leave out any they do not want:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
EasyFlow.host(:console) do |host|
|
|
40
|
+
host.layout = "application"
|
|
41
|
+
host.admin_layout = "admin"
|
|
42
|
+
host.admin_authentication_method = :authenticate_admin!
|
|
43
|
+
host.visitor_authorization_method = :easy_flow_visitor_permitted?
|
|
44
|
+
host.refusal_method = :refuse_flow
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- `layout` — the visitor layout. Defaults to the engine's bare layout, which loads no stylesheet, so a styled app almost always sets it.
|
|
49
|
+
- `admin_layout` — the admin layout. Defaults to `"application"`. It must call `yield :head` inside `<head>`, or the canvas scripts do not load.
|
|
50
|
+
- `admin_authentication_method` — a method on the base controller, called with no arguments before every admin page. With none set, the admin pages are open to anyone.
|
|
51
|
+
- `visitor_authorization_method` — a method on the base controller, called with the flow, returning true when the visitor may run it. With none set, every visitor is refused.
|
|
52
|
+
- `refusal_method` — a method on the base controller, called with the refusal error when a visitor is refused or a flow is unpublished or withdrawn. With none set, the response is `404 Not Found`.
|
|
53
|
+
|
|
54
|
+
Each method named here must exist on the base controller. Ask the developer to point at it or write it. Do not invent its logic.
|
|
55
|
+
7. Mount the engine in `config/routes.rb`, once per host. The host name in `defaults` must match a name declared in step 6. When there is more than one mount, give each an `as:` name:
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
mount EasyFlow::Engine => "/flows", defaults: { easy_flow_host: "flows" }
|
|
59
|
+
mount EasyFlow::Engine => "/console", as: :console_flows, defaults: { easy_flow_host: "console" }
|
|
60
|
+
```
|
|
61
|
+
|
|
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:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
EasyFlow.draws_with("steps/step")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
9. 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.
|
|
70
|
+
10. Start the server and open `<mount path>/manage/flows` for each host.
|
|
71
|
+
|
|
72
|
+
## Conventions
|
|
73
|
+
|
|
74
|
+
- After install, check that `<mount path>/manage/flows` shows the flow list and that a new flow opens on the canvas. If the canvas is blank, check that the admin layout calls `yield :head`.
|
|
75
|
+
- After publishing a flow, check that `<mount path>/<slug>` shows it to a visitor who passes the host's visitor authorization method.
|
|
76
|
+
- After upgrading easy_flow, run `bin/rails easy_flow:install:migrations` again and then `bin/rails db:migrate`. Only migrations the app does not already have are copied.
|
|
77
|
+
- The initializer runs once at boot, so a change to it needs a server restart.
|
|
78
|
+
- Declaring step types, serving a host's flows from the app's own controllers and routes, and reading runs and answers are out of scope here. They belong to the `easy_flow-develop` local.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
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
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
- bin/rails easy_flow:install:migrations
|
|
5
|
+
- mount EasyFlow::Engine
|
|
6
|
+
- EasyFlow.base_controller=
|
|
7
|
+
- EasyFlow.host
|
|
8
|
+
- EasyFlow.draws_with
|
|
9
|
+
- EasyFlow.check
|
|
10
|
+
- /manage/flows
|
|
11
|
+
|
|
12
|
+
develop:
|
|
13
|
+
- EasyFlow::Step
|
|
14
|
+
- EasyFlow.step
|
|
15
|
+
- EasyFlow::FlowsController
|
|
16
|
+
- hosted_by
|
|
17
|
+
- routed_by
|
|
18
|
+
- EasyFlow::Run
|
|
19
|
+
- EasyFlow::QuestionRunner
|
|
20
|
+
|
|
21
|
+
sources:
|
|
22
|
+
- lib/easy_flow.rb
|
|
23
|
+
- lib/easy_flow/engine.rb
|
|
24
|
+
- lib/easy_flow/host.rb
|
|
25
|
+
- lib/easy_flow/host_routes.rb
|
|
26
|
+
- app/controllers/concerns/easy_flow/hosted.rb
|
|
27
|
+
- app/controllers/easy_flow/application_controller.rb
|
|
28
|
+
- app/controllers/easy_flow/flows_controller.rb
|
|
29
|
+
- app/controllers/easy_flow/manage/base_controller.rb
|
|
30
|
+
- app/models/easy_flow/step.rb
|
|
31
|
+
- app/models/easy_flow/step_type/declaration.rb
|
|
32
|
+
- app/models/easy_flow/steps/question.rb
|
|
33
|
+
- app/models/easy_flow/run.rb
|
|
34
|
+
- app/models/easy_flow/runner.rb
|
|
35
|
+
- app/models/easy_flow/question_runner.rb
|
|
36
|
+
- config/routes.rb
|
|
37
|
+
- db/migrate/20260924120000_create_easy_flow_definitions.rb
|
|
38
|
+
- db/migrate/20260924120100_create_easy_flow_versions.rb
|
|
39
|
+
- db/migrate/20260924120200_create_easy_flow_runs.rb
|
|
40
|
+
- db/migrate/20260924130000_add_host_to_easy_flow_definitions.rb
|
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.4.
|
|
4
|
+
version: 0.4.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- tylercschneider
|
|
@@ -140,6 +140,10 @@ files:
|
|
|
140
140
|
- lib/easy_flow/host_routes.rb
|
|
141
141
|
- lib/easy_flow/unset_host.rb
|
|
142
142
|
- lib/easy_flow/version.rb
|
|
143
|
+
- the_local/agents/easy_flow-develop.md
|
|
144
|
+
- the_local/agents/easy_flow-info.md
|
|
145
|
+
- the_local/agents/easy_flow-install.md
|
|
146
|
+
- the_local/interface.yml
|
|
143
147
|
homepage: https://github.com/DYB-Development/easy_flow
|
|
144
148
|
licenses:
|
|
145
149
|
- MIT
|